Management.cs 346 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350
  1. using Cognex.VisionPro;
  2. using Cognex.VisionPro.ToolBlock;
  3. using CSScripting;
  4. using NPOI.OpenXml4Net.OPC.Internal;
  5. using NPOI.OpenXmlFormats.Dml.Diagram;
  6. using NPOI.SS.Formula.Eval;
  7. using NPOI.SS.Formula.Functions;
  8. using NPOI.Util;
  9. using Org.BouncyCastle.Ocsp;
  10. //using ICSharpCode.SharpZipLib.Zip;
  11. using Prism.Events;
  12. using Prism.Ioc;
  13. using Prism.Mvvm;
  14. using Prism.Regions;
  15. using Prism.Services.Dialogs;
  16. using SqlSugar;
  17. using SqlSugar.SplitTableExtensions;
  18. using System;
  19. using System.Collections.Concurrent;
  20. using System.Collections.Generic;
  21. using System.Collections.ObjectModel;
  22. using System.Diagnostics;
  23. using System.Drawing;
  24. using System.IO;
  25. using System.IO.Compression;
  26. using System.IO.MemoryMappedFiles;
  27. using System.IO.MemoryMappedFiles;
  28. using System.Linq;
  29. using System.Text;
  30. using System.Text.Json;
  31. using System.Threading;
  32. using System.Threading.Tasks;
  33. using System.Web.UI.WebControls;
  34. using System.Windows;
  35. using System.Windows.Media;
  36. using Team.FFFeederService.Interfaces;
  37. using TeamAAS_VP.Controls;
  38. using TeamAAS_VP.Core.PLCs;
  39. using TeamAAS_VP.Core.ScrewDriver;
  40. using TeamAAS_VP.Enums;
  41. using TeamAAS_VP.Events;
  42. using TeamAAS_VP.Interfaces;
  43. using TeamAAS_VP.Models;
  44. using TeamAAS_VP.Resources.Languages;
  45. using TeamAAS_VP.ViewModels;
  46. using TeamAAS_VP.ViewModels.Home;
  47. using TouchSocket.Core;
  48. using TouchSocket.SerialPorts;
  49. using TouchSocket.Sockets;
  50. namespace TeamAAS_VP.Core
  51. {
  52. public class Management : BindableBase
  53. {
  54. #region 字段
  55. IRegionManager _regionManager;
  56. IEventAggregator _eventAggregator;
  57. IContainerProvider _container;
  58. IConfigService _configService;
  59. IRobotService _robotService;
  60. IScannerService _scannerService;
  61. ICameraService _cameraService;
  62. IFeederService _feederService;
  63. IPlcService _plcService;
  64. ILightManagerService _lightManagerService;
  65. IProductService _productService;
  66. ICalibrationService _calibrationService;
  67. IRemoteCommandService _remoteCommandService;
  68. ISystemDatabaseService _systemDatabaseService;
  69. IMesService _mesService;
  70. IDialogService _dialogService;
  71. Timer yieldtimer;
  72. /// <summary>
  73. /// 消息队列——替代 SendTaskMessage 中的 Dispatcher.BeginInvoke,消除 UI 线程阻塞
  74. /// </summary>
  75. private readonly ConcurrentQueue<MessageStruct> _messageQueue = new ConcurrentQueue<MessageStruct>();
  76. private Timer _messageFlushTimer;
  77. private DateTime StartTime = DateTime.Now;
  78. /// <summary>
  79. /// 产品主sn
  80. /// </summary>
  81. string ProductMainSN = "";
  82. //string[] ProductMainSN1 { get; set; } = new string[10];
  83. /// <summary>
  84. /// 工单信息
  85. /// </summary>
  86. string[] wo = new string[10];
  87. string[] model_num = new string[10];//产品model_num
  88. string[] color = new string[10];//产品color
  89. string[] ppid = new string[10];//产品ppid
  90. string[] revision = new string[10];//产品revision
  91. string[] stage = new string[10];//产品revision
  92. string[] kb_sn = new string[10];//产品kb_sn
  93. string[] kb_pn = new string[10];
  94. /// <summary>
  95. /// 上次执行上传csv的日期
  96. /// </summary>
  97. private DateTime _lastCompressDate = DateTime.MinValue;
  98. /// <summary>
  99. /// 当天是否上传过csv
  100. /// </summary>
  101. private bool _hasCompressedToday = false;
  102. #endregion
  103. #region 属性
  104. private Guid _defaultScannerId = Guid.Empty;
  105. private volatile TaskCompletionSource<string> _scanTcs; // 最简单:只支持单通道“当前一次扫
  106. public string[] CsvData = new string[50];
  107. public int[] ResultData = new int[200];
  108. public string code = "";
  109. ConcurrentBag<LockResult> lockResultsAll = new ConcurrentBag<LockResult>();//一个产品的总结果
  110. CountdownEvent countdown = new CountdownEvent(10);
  111. ConcurrentBag<bool> AllResult = new ConcurrentBag<bool>();
  112. private ObservableCollection<ShowRender> _Renders;
  113. private double _CTtime;
  114. public int ResultDataCount;
  115. public string PhotoPath = "";
  116. // 扫码结果
  117. private string ScanValue = "";
  118. // 扫码完成事件
  119. private readonly ManualResetEventSlim _scanDoneEvent = new ManualResetEventSlim(false);
  120. //键盘数据
  121. public ConcurrentDictionary<string, double> keyData = new ConcurrentDictionary<string, double> { };
  122. //键盘单独数据
  123. public ConcurrentDictionary<string, double> keyData1 = new ConcurrentDictionary<string, double> { };
  124. public int completed = 0;
  125. //键盘差值
  126. public bool isValueOk;
  127. private SerialPortClient _Scan_Client;
  128. public SerialPortClient Scan_Client
  129. {
  130. get { return _Scan_Client; }
  131. set { _Scan_Client = value; }
  132. }
  133. private bool _ShowMes_Query;
  134. /// <summary>
  135. /// 显示查询结果
  136. /// </summary>
  137. public bool ShowMes_Query
  138. {
  139. get { return _ShowMes_Query; }
  140. set { SetProperty(ref _ShowMes_Query, value); }
  141. }
  142. private bool _ShowMes_Result = false;
  143. /// <summary>
  144. /// 显示上传结果
  145. /// </summary>
  146. public bool ShowMes_Result
  147. {
  148. get { return _ShowMes_Result; }
  149. set { SetProperty(ref _ShowMes_Result, value); }
  150. }
  151. /// <summary>
  152. /// ct
  153. /// </summary>
  154. public double CTtime
  155. {
  156. get { return _CTtime; }
  157. set { SetProperty(ref _CTtime, value); }
  158. }
  159. private double _CTtime2;
  160. /// <summary>
  161. /// ct2
  162. /// </summary>
  163. public double CTtime2
  164. {
  165. get { return _CTtime2; }
  166. set { SetProperty(ref _CTtime2, value); }
  167. }
  168. /// <summary>
  169. /// 显示界面
  170. /// </summary>
  171. public ObservableCollection<ShowRender> Renders
  172. {
  173. get { return _Renders; }
  174. set { SetProperty(ref _Renders, value); }
  175. }
  176. private ProductModel _CurrentProduct;
  177. /// <summary>
  178. /// 当前产品
  179. /// </summary>
  180. public ProductModel CurrentProduct
  181. {
  182. get { return _CurrentProduct; }
  183. set { SetProperty(ref _CurrentProduct, value); }
  184. }
  185. public BgCommunicate BgCommunicate { get; private set; }
  186. public BgModbusTcpCommunicate BgModbusTcpCommunicate { get; private set; }
  187. private ObservableCollection<StatusInfo> _Status = new ObservableCollection<StatusInfo>();
  188. /// <summary>
  189. /// 状态栏集合
  190. /// </summary>
  191. public ObservableCollection<StatusInfo> Status
  192. {
  193. get { return _Status; }
  194. set { SetProperty(ref _Status, value); }
  195. }
  196. private Int64 _TotalQuantity;
  197. /// <summary>
  198. /// 总产量
  199. /// </summary>
  200. public Int64 TotalQuantity
  201. {
  202. get { return _TotalQuantity; }
  203. set { SetProperty(ref _TotalQuantity, value); }
  204. }
  205. private Int64 _TotalQuantityToday;
  206. /// <summary>
  207. /// 当天的总产量
  208. /// </summary>
  209. public Int64 TotalQuantityToday
  210. {
  211. get { return _TotalQuantityToday; }
  212. set { SetProperty(ref _TotalQuantityToday, value); }
  213. }
  214. private Int64 _CurrentUPH;
  215. /// <summary>
  216. /// 当前的UPH
  217. /// </summary>
  218. public Int64 CurrentUPH
  219. {
  220. get { return _CurrentUPH; }
  221. set { SetProperty(ref _CurrentUPH, value); }
  222. }
  223. private XYD_ScrewDriver _ScrewDriver;
  224. public XYD_ScrewDriver ScrewDriver
  225. {
  226. get { return _ScrewDriver; }
  227. set { SetProperty(ref _ScrewDriver, value); }
  228. }
  229. public Dictionary<string, object> BackupObject { get; set; } = new Dictionary<string, object>();
  230. private ObservableCollection<ProductModel> _ProductList;
  231. public ObservableCollection<ProductModel> ProductList
  232. {
  233. get { return _ProductList; }
  234. set { SetProperty(ref _ProductList, value); }
  235. }
  236. /// <summary>
  237. /// 设备状态
  238. /// </summary>
  239. private RunDisplayMode _CurrentDisplayMode;
  240. public RunDisplayMode CurrentDisplayMode
  241. {
  242. get { return _CurrentDisplayMode; }
  243. set { SetProperty(ref _CurrentDisplayMode, value); }
  244. }
  245. private string _finalResultStatus = "Pending";
  246. private string _finalResultText = "";
  247. public string FinalResultStatus
  248. {
  249. get { return _finalResultStatus; }
  250. set { SetProperty(ref _finalResultStatus, value); }
  251. }
  252. public string FinalResultText
  253. {
  254. get { return _finalResultText; }
  255. set { SetProperty(ref _finalResultText, value); }
  256. }
  257. #endregion
  258. #region 命令
  259. #endregion
  260. #region 事件
  261. #endregion
  262. public Management(IRegionManager regionManager, IEventAggregator ea, IContainerProvider container, IConfigService configService, IDialogService dialogService,
  263. IRobotService robotService, ICameraService cameraService, IFeederService feederService, IPlcService plcService, IProductService productService,
  264. ICalibrationService calibrationService, IRemoteCommandService remoteCommandService, ISystemDatabaseService systemDatabaseService, ILightManagerService lightManagerService, IMesService mesService, IScannerService scannerService)
  265. {
  266. _regionManager = regionManager;
  267. _eventAggregator = ea;
  268. _container = container;
  269. _configService = configService;
  270. _robotService = robotService;
  271. _scannerService = scannerService;
  272. _cameraService = cameraService;
  273. _feederService = feederService;
  274. _plcService = plcService;
  275. _dialogService = dialogService;
  276. _calibrationService = calibrationService;
  277. yieldtimer = new Timer(DoYieldTime, null, 10000, 1000);
  278. _messageFlushTimer = new Timer(_ => FlushMessageQueue(), null, 200, 200);
  279. Renders = new ObservableCollection<ShowRender>();
  280. _configService = configService;
  281. _productService = productService;
  282. _remoteCommandService = remoteCommandService;
  283. _systemDatabaseService = systemDatabaseService;
  284. _lightManagerService = lightManagerService;
  285. _mesService = mesService;
  286. _eventAggregator.GetEvent<CurrentStatusNotification>().Subscribe(CurrentRunStatus);
  287. }
  288. #region 初始化硬件模块
  289. /// <summary>
  290. /// 初始化Feeder
  291. /// </summary>
  292. /// <returns></returns>
  293. public async Task<(bool IsSucceed, string Msg)> InitFeeders()
  294. {
  295. var feeders = _configService.GetAllFeeders();
  296. StringBuilder sb = new StringBuilder();
  297. foreach (var item in feeders)
  298. {
  299. _feederService.CreateFeeder(item.Id, item.FeederNo, item.FeederName, item.IP, item.Port, item.FeederBrand);
  300. var feeder = _feederService.GetFeeder(item.Id);
  301. Status.Add(new StatusInfo(item.Id, item.FeederName + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
  302. try
  303. {
  304. feeder.FeederConnectionStatusChanged += Management_FeederConnectionStatusChanged;
  305. await feeder.ConnectAsync(); //连接Feeder
  306. //SendTaskMessage($"{item.FeederName}已连接!", MessageLevel.Debug);
  307. }
  308. catch (Exception ex)
  309. {
  310. sb.AppendLine($"{item.FeederName}:{Lang.断开连接}![{ex.Message}]");
  311. SendTaskMessage($"{item.FeederName}{Lang.断开连接}!", MessageLevel.Alarm);
  312. }
  313. }
  314. if (sb.Length == 0)
  315. {
  316. return (true, "");
  317. }
  318. else
  319. {
  320. return (false, sb.ToString());
  321. }
  322. }
  323. /// <summary>
  324. /// 初始化机器人
  325. /// </summary>
  326. /// <returns></returns>
  327. public async Task<(bool IsSucceed, string Msg)> InitRobots()
  328. {
  329. var robots = _configService.GetAllRobots();
  330. StringBuilder sb = new StringBuilder();
  331. foreach (var item in robots)
  332. {
  333. _robotService.CreateRobot(item.Id, item);
  334. try
  335. {
  336. Status.Add(new StatusInfo(item.Id, item.RobotName + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
  337. var robot = _robotService.GetRobot(item.Id);
  338. robot.ReceivedEvent += Management_ReceivedEvent;
  339. robot.SendEvent += Management_SendEvent;
  340. robot.ConnectedEvent += Management_ConnectedEvent;
  341. robot.DisconnectedEvent += Management_DisconnectedEvent;
  342. await robot.ConnectAsync(); //连接Robot
  343. SendTaskMessage($"{item.RobotName}{Lang.已连接}!", MessageLevel.Debug);
  344. }
  345. catch (Exception ex)
  346. {
  347. sb.AppendLine($"{item.RobotName}:{Lang.断开连接}![{ex.Message}]");
  348. SendTaskMessage($"{item.RobotName}{Lang.断开连接}!", MessageLevel.Alarm);
  349. }
  350. }
  351. if (sb.Length == 0)
  352. {
  353. return (true, "");
  354. }
  355. else
  356. {
  357. return (false, sb.ToString());
  358. }
  359. }
  360. /// <summary>
  361. /// 初始化扫码枪
  362. /// </summary>
  363. /// <returns></returns>
  364. public async Task<(bool IsSucceed, string Msg)> InitScanners()
  365. {
  366. var scanners = _configService.GetAllScanners();
  367. StringBuilder sb = new StringBuilder();
  368. foreach (var item in scanners)
  369. {
  370. _scannerService.CreateScanner(item.Id, item);
  371. try
  372. {
  373. Status.Add(new StatusInfo(item.Id, item.ScannerName + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
  374. var scanner = _scannerService.GetScanner(item.Id);
  375. scanner.ReceivedEvent += Management_ScannerReceivedEvent;
  376. scanner.SendEvent += Management_ScannerSendEvent;
  377. scanner.ConnectedEvent += Management_ScannerConnectedEvent;
  378. scanner.DisconnectedEvent += Management_ScannerDisconnectedEvent;
  379. await scanner.ConnectAsync(); //连接Scanner
  380. SendTaskMessage($"{item.ScannerName}{Lang.已连接}!", MessageLevel.Debug);
  381. }
  382. catch (Exception ex)
  383. {
  384. sb.AppendLine($"{item.ScannerName}:{Lang.断开连接}![{ex.Message}]");
  385. SendTaskMessage($"{item.ScannerName}{Lang.断开连接}!", MessageLevel.Alarm);
  386. }
  387. }
  388. if (sb.Length == 0)
  389. {
  390. return (true, "");
  391. }
  392. else
  393. {
  394. return (false, sb.ToString());
  395. }
  396. }
  397. /// <summary>
  398. /// 初始化PLC
  399. /// </summary>
  400. /// <returns></returns>
  401. public async Task<(bool IsSucceed, string Msg)> InitPlc()
  402. {
  403. var plcs = _configService.GetAllPlcs();
  404. StringBuilder sb = new StringBuilder();
  405. foreach (var item in plcs)
  406. {
  407. try
  408. {
  409. _plcService.CreatePlc(item.Id, item);
  410. var plc = _plcService.GetPlc(item.Id);
  411. Status.Add(new StatusInfo(item.Id, item.Name + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
  412. plc.ConnectChangedEvent += Management_PlcConnectChangedEvent;
  413. await plc.ConnectAsync(); //连接PLC
  414. //SendTaskMessage($"{item.Name}{Lang.已连接}!", MessageLevel.Debug);
  415. }
  416. catch (Exception ex)
  417. {
  418. sb.AppendLine($"{item.Name}:{Lang.断开连接}![{ex.Message}]");
  419. SendTaskMessage($"{item.Name}{Lang.断开连接}!", MessageLevel.Alarm);
  420. }
  421. }
  422. try
  423. {
  424. await WriteSystemParameterToPlcAsync(_configService.GetSystemConfiguration());
  425. RegisterPlcMonitorAddress();
  426. }
  427. catch (Exception ex)
  428. {
  429. LogHelper.WriteLogError("为PLC写入系统参数和订阅变量时出错", ex);
  430. }
  431. if (sb.Length == 0)
  432. {
  433. return (true, "");
  434. }
  435. else
  436. {
  437. return (false, sb.ToString());
  438. }
  439. }
  440. /// <summary>
  441. /// 初始化相机
  442. /// </summary>
  443. /// <returns></returns>
  444. public async Task<(bool IsSucceed, string Msg)> InitCameras()
  445. {
  446. var cameras = _configService.GetAllCameras();
  447. StringBuilder sb = new StringBuilder();
  448. foreach (var item in cameras)
  449. {
  450. if (item.DisplatConfigs != null)
  451. {
  452. foreach (var item1 in item.DisplatConfigs)
  453. {
  454. Renders.Add(new ShowRender() { Id = item1.Id, DisplayName = item1.DisplayName });
  455. }
  456. }
  457. _cameraService.CreateCamera(item.Id, item);
  458. try
  459. {
  460. var camera = _cameraService.GetCamera(item.Id);
  461. Status.Add(new StatusInfo(item.Id, item.CameraName + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
  462. camera.CameraConnectChangedEvent += Management_CameraConnectChangedEvent;
  463. camera.ImageCallbackEvent += Camera_ImageCallbackEvent;
  464. try
  465. {
  466. if (await camera.OpenDeviceAsync())
  467. {
  468. SendTaskMessage($"{item.CameraName}{Lang.已连接}!", MessageLevel.Debug);
  469. }
  470. else
  471. {
  472. SendTaskMessage($"{item.CameraName}{Lang.连接失败}!", MessageLevel.Alarm);
  473. sb.AppendLine($"{item.CameraName}:{Lang.连接失败}!");
  474. }
  475. }
  476. catch (Exception ex)
  477. {
  478. SendTaskMessage($"{item.CameraName}{ex.Message}!", MessageLevel.Alarm);
  479. sb.AppendLine($"{item.CameraName}:{ex.Message}!");
  480. }
  481. }
  482. catch (Exception ex)
  483. {
  484. SendTaskMessage($"{item.CameraName}{Lang.连接失败}!", MessageLevel.Alarm);
  485. sb.AppendLine($"{item.CameraName}:{Lang.连接失败}!:{ex.Message}");
  486. }
  487. }
  488. _container.Resolve<ShowVisionRenderViewModel>().Renders = Renders;
  489. if (sb.Length == 0)
  490. {
  491. return (true, "");
  492. }
  493. else
  494. {
  495. return (false, sb.ToString());
  496. }
  497. }
  498. private void Camera_ImageCallbackEvent(ICogImage arg1, TimeSpan arg2, string arg3, Guid cameraId)
  499. {
  500. var camera = _configService.GetCamera(cameraId);
  501. //SendTaskMessage($"相机[{camera.CameraName}]图像接收完成!", MessageLevel.Info);
  502. LogHelper.WriteLogInfo($"相机[{camera.CameraName}]图像接收完成!");
  503. //if (camera.CameraNo == 1)
  504. //{
  505. // ImageData[1] = 1;
  506. //}
  507. //else if (camera.CameraNo == 2)
  508. //{
  509. // ImageData[2] = 1;
  510. //}
  511. //else if (camera.CameraNo == 3)
  512. //{
  513. // ImageData[3] = 1;
  514. // ImageData[4] = 1;
  515. //}
  516. //_eventAggregator.GetEvent<RenderUpdateNotification>().Publish(new ShowRender()
  517. //{
  518. // CameraName = camera.CameraName,
  519. // Id = cameraId,
  520. // Image = arg1,
  521. // Graphic = null,
  522. // Record = null,
  523. // Result = false,
  524. // IsShow = true,
  525. //});
  526. // 通知等待方:该相机新图到达
  527. //SignalImageArrived(cameraId, arg1);
  528. }
  529. /// <summary>
  530. /// 初始化光源控制器
  531. /// </summary>
  532. /// <returns></returns>
  533. public async Task<(bool IsSucceed, string Msg)> InitLightControllers()
  534. {
  535. var lightcontrollers = _configService.GetAllLightControllers();
  536. StringBuilder sb = new StringBuilder();
  537. foreach (var item in lightcontrollers)
  538. {
  539. try
  540. {
  541. var lishtCtr = await _lightManagerService.RegisterControllerAsync(item.Id, item);
  542. //var lightcontroller = _cameraService.GetLightController(item.Id);
  543. //await lightcontroller.ConnectAsync(); //连接光源控制器
  544. //SendTaskMessage($"{item.LightControllerName}{Lang.已连接}!", MessageLevel.Debug);
  545. }
  546. catch (Exception ex)
  547. {
  548. //sb.AppendLine($"{item.LightControllerName}:{Lang.断开连接}![{ex.Message}]");
  549. //SendTaskMessage($"{item.LightControllerName}{Lang.断开连接}!", MessageLevel.Alarm);
  550. }
  551. }
  552. if (lightcontrollers.Count > 0)
  553. {
  554. var result = await _lightManagerService.ConnectAllAsync();
  555. if (result)
  556. {
  557. return (true, "");
  558. }
  559. else
  560. {
  561. return (false, "Light Controller Connect Failed!");
  562. }
  563. }
  564. return (true, "");
  565. //if (sb.Length == 0)
  566. //{
  567. // return (true, "");
  568. //}
  569. //else
  570. //{
  571. // return (false, sb.ToString());
  572. //}
  573. }
  574. /// <summary>
  575. /// 初始化后台TCP服务器通讯
  576. /// </summary>
  577. public void InitBgTcp()
  578. {
  579. var config = _configService.GetBgTcp();
  580. try
  581. {
  582. BgCommunicate = new BgCommunicate(config);
  583. BgCommunicate.ConnectedEvent += BgCommunicate_ConnectedEvent;
  584. BgCommunicate.DisconnectedEvent += BgCommunicate_DisconnectedEvent;
  585. BgCommunicate.ReceivedEvent += BgCommunicate_ReceivedEvent;
  586. BgCommunicate.SendEvent += BgCommunicate_SendEvent;
  587. BgCommunicate.StartListening();
  588. SendTaskMessage($"{Lang.已开启监听端口}:{config.Port}", MessageLevel.Debug);
  589. }
  590. catch (Exception ex)
  591. {
  592. SendTaskMessage($"{Lang.未开启监听端口}:{config.Port}", MessageLevel.Error);
  593. LogHelper.WriteLogError("开启后台服务器通讯时出错!", ex);
  594. }
  595. }
  596. /// <summary>
  597. /// 初始化后台ModbusTCP从站
  598. /// </summary>
  599. public void InitModbusTcp()
  600. {
  601. try
  602. {
  603. var config = _configService.GetBgModbusTcp();
  604. BgModbusTcpCommunicate = new BgModbusTcpCommunicate(config);
  605. if (config.IsEnabled)
  606. {
  607. BgModbusTcpCommunicate.Listen();
  608. SendTaskMessage($"Start Modbus Tcp Slave:{BgModbusTcpCommunicate.IP}:{BgModbusTcpCommunicate.Port}:{BgModbusTcpCommunicate.SlaveID}", MessageLevel.Debug);
  609. }
  610. }
  611. catch (Exception ex)
  612. {
  613. SendTaskMessage($"No Start Modbus Tcp Slave:{ex.Message}", MessageLevel.Alarm);
  614. LogHelper.WriteLogError("开启后台Modbus TCP通讯时出错!", ex);
  615. }
  616. }
  617. /// <summary>
  618. /// 初始化后台脚本
  619. /// </summary>
  620. public void InitBackgroundcript()
  621. {
  622. try
  623. {
  624. if (!Directory.Exists(FilePath.BackgroundScriptPath))
  625. {
  626. Directory.CreateDirectory(FilePath.BackgroundScriptPath);
  627. }
  628. try
  629. {
  630. string[] files = Directory.GetFiles(FilePath.BackgroundScriptPath);
  631. List<string> ScriptFilesCollection = new List<string>();
  632. foreach (string file in files)
  633. {
  634. string fileName = Path.GetFileName(file);
  635. string fileExtension = Path.GetExtension(file);
  636. if (fileExtension == ".cs")
  637. {
  638. ScriptFilesCollection.Add(file);
  639. }
  640. }
  641. foreach (var item in ScriptFilesCollection)
  642. {
  643. try
  644. {
  645. string script = FileHelper.ReadFile(item);
  646. SendTaskMessage($"{Lang.执行脚本}:{item}", MessageLevel.Info);
  647. Task.Factory.StartNew(() =>
  648. {
  649. ScriptHelper.ExecuteScriptingAsync(script, _regionManager, _eventAggregator, _container, rst =>
  650. {
  651. if (!rst.Item1)
  652. {
  653. foreach (var err in rst.Item2)
  654. {
  655. SendTaskMessage($"{Lang.后台脚本出错}:{err}", MessageLevel.Error);
  656. }
  657. }
  658. });
  659. });
  660. }
  661. catch (Exception ex)
  662. {
  663. LogHelper.WriteLogError($"开启脚本时出错:{item}", ex);
  664. }
  665. }
  666. }
  667. catch (Exception ex)
  668. {
  669. LogHelper.WriteLogError("读取本地脚本文件列表时出错", ex);
  670. }
  671. }
  672. catch (Exception ex)
  673. {
  674. LogHelper.WriteLogError("开启后台脚本时出错!", ex);
  675. }
  676. }
  677. /// <summary>
  678. /// 初始化电批
  679. /// </summary>
  680. /// <returns></returns>
  681. public async Task InitScrewDriver()
  682. {
  683. try
  684. {
  685. var screwDriverConfig = _configService.GetScrewDriverConfig();
  686. ScrewDriver = new XYD_ScrewDriver(screwDriverConfig.IPAdress, screwDriverConfig.Port);
  687. Status.Add(new StatusInfo(ScrewDriver.Id, "电批未连接", new SolidColorBrush(Colors.Red)));
  688. ScrewDriver.ConnectStateChangedEvent += ScrewDriver_ConnectStateChangedEvent;
  689. ScrewDriver.SendTimeout = screwDriverConfig.SendTimeout;
  690. screwDriverConfig.ReceiveTimeout = screwDriverConfig.ReceiveTimeout;
  691. var isConnected = await ScrewDriver.ConnectAsync();
  692. if (isConnected)
  693. {
  694. SendTaskMessage($"电批已连接", MessageLevel.Debug);
  695. }
  696. else
  697. {
  698. SendTaskMessage($"电批连接失败", MessageLevel.Error);
  699. }
  700. }
  701. catch (Exception ex)
  702. {
  703. SendTaskMessage($"电批连接失败:{ex.Message}", MessageLevel.Alarm);
  704. LogHelper.WriteLogError("连接电批时出错!", ex);
  705. }
  706. }
  707. public async Task InitScan()
  708. {
  709. if (!File.Exists(FilePath.ScanRS232ConfigPath))
  710. {
  711. var scan = new ScanRs232ConfigModel();
  712. FileHelper.WriteJsonFile(scan, FilePath.ScanRS232ConfigPath);
  713. }
  714. try
  715. {
  716. var res = FileHelper.ReadJsonFile<ScanRs232ConfigModel>(FilePath.ScanRS232ConfigPath);
  717. if (res != null)
  718. {
  719. Scan_Client = new SerialPortClient();
  720. Scan_Client.Connecting = (client1, e) => { return EasyTask.CompletedTask; };//即将连接到端口
  721. Scan_Client.Connected = (client1, e) => { return EasyTask.CompletedTask; };//成功连接到端口
  722. Scan_Client.Closing = (client1, e) => { return EasyTask.CompletedTask; };//即将从端口断开连接。此处仅主动断开才有效。
  723. Scan_Client.Closed = (client1, e) => { return EasyTask.CompletedTask; };//从端口断开连接,当连接不成功时不会触发。
  724. Scan_Client.Received = async (c, e) =>
  725. {
  726. //await Console.Out.WriteLineAsync(Encoding.UTF8.GetString(e.ByteBlock.Buffer));
  727. await Console.Out.WriteLineAsync(e.ByteBlock.Span.ToString(Encoding.ASCII));
  728. };
  729. Scan_Client.Received = Scan_DataReceived;
  730. await Scan_Client.SetupAsync(new TouchSocketConfig()
  731. .SetSerialPortOption(new SerialPortOption()
  732. {
  733. BaudRate = res.BaudRate,//波特率
  734. DataBits = res.DataBits,//数据位
  735. Parity = res.Parity,//校验位
  736. PortName = res.PortName,//COM
  737. StopBits = res.StopBits//停止位
  738. })
  739. .SetSerialDataHandlingAdapter(() => new PeriodPackageAdapter() { CacheTimeout = TimeSpan.FromMilliseconds(100) })
  740. );
  741. await Scan_Client.ConnectAsync();
  742. if (Scan_Client.Online)
  743. {
  744. SendTaskMessage(Lang.扫码机已连接, MessageLevel.Debug);
  745. }
  746. else
  747. {
  748. SendTaskMessage(Lang.扫码机未连接, MessageLevel.Debug);
  749. }
  750. }
  751. else
  752. {
  753. SendTaskMessage(Lang.请设置扫码机串口, MessageLevel.Error);
  754. }
  755. }
  756. catch (Exception ex)
  757. {
  758. LogHelper.WriteLogError("初始化扫码枪时出错!", ex);
  759. SendTaskMessage(Lang.初始化扫码枪时出错 + ex.Message, MessageLevel.Error);
  760. }
  761. }
  762. #endregion
  763. #region 机器人指令执行
  764. public Dictionary<Guid, CancellationTokenSource> RobotTCPCollection = new Dictionary<Guid, CancellationTokenSource>();
  765. public Dictionary<Guid, CancellationTokenSource> ScannerTCPCollection = new Dictionary<Guid, CancellationTokenSource>();
  766. /// <summary>
  767. /// 机器人TCP接收
  768. /// </summary>
  769. /// <param name="arg1"></param>
  770. /// <param name="arg2"></param>
  771. /// <param name="arg3"></param>
  772. private async void Management_ReceivedEvent(Guid robotid, object arg2, TouchSocket.Sockets.ReceivedDataEventArgs e)
  773. {
  774. try
  775. {
  776. if (!RobotTCPCollection.ContainsKey(robotid))
  777. RobotTCPCollection.Add(robotid, new CancellationTokenSource());
  778. else
  779. {
  780. if (RobotTCPCollection[robotid].IsCancellationRequested)
  781. {
  782. RobotTCPCollection[robotid] = new CancellationTokenSource();
  783. }
  784. }
  785. var robot = await _robotService.GetRobotAsync(robotid);
  786. //从服务器收到信息。但是一般byteBlock和requestInfo会根据适配器呈现不同的值。
  787. var buffer = e.ByteBlock.Span.ToString(robot.GetEncoding());
  788. SendTaskMessage($"{robot.Name}Received:{buffer}", MessageLevel.Info);
  789. var _ = _remoteCommandService.ExecuteAsync(buffer, RobotTCPCollection[robotid].Token, async msg =>
  790. {
  791. try
  792. {
  793. if (robot.ConnectType == TCPConnectType.Client)
  794. {
  795. if (robot.IsConnected)
  796. {
  797. await robot.SendAsync($"{msg}");
  798. }
  799. }
  800. else
  801. {
  802. var cient = (ITcpSessionClient)arg2;
  803. if (cient.Online)
  804. {
  805. await robot.SendAsync(cient, $"{msg}");
  806. }
  807. }
  808. }
  809. catch (Exception ex)
  810. {
  811. LogHelper.WriteLogError("TCP发送数据时出错!", ex);
  812. SendTaskMessage(ex.Message, MessageLevel.Alarm);
  813. }
  814. });
  815. }
  816. catch (Exception ex)
  817. {
  818. LogHelper.WriteLogError("处理机器人接收的命令时出错!", ex);
  819. SendTaskMessage(ex.Message, MessageLevel.Alarm);
  820. }
  821. }
  822. /// <summary>
  823. /// 扫码枪TCP接收
  824. /// </summary>
  825. /// <param name="arg1"></param>
  826. /// <param name="arg2"></param>
  827. /// <param name="arg3"></param>
  828. private async void Management_ScannerReceivedEvent(Guid scannerid, object arg2, TouchSocket.Sockets.ReceivedDataEventArgs e)
  829. {
  830. try
  831. {
  832. if (!ScannerTCPCollection.ContainsKey(scannerid))
  833. ScannerTCPCollection.Add(scannerid, new CancellationTokenSource());
  834. else
  835. {
  836. if (ScannerTCPCollection[scannerid].IsCancellationRequested)
  837. {
  838. ScannerTCPCollection[scannerid] = new CancellationTokenSource();
  839. }
  840. }
  841. var scanner = await _scannerService.GetScannerAsync(scannerid);
  842. //从服务器收到信息。但是一般byteBlock和requestInfo会根据适配器呈现不同的值。
  843. var buffer = e.ByteBlock.Span.ToString(scanner.GetEncoding());
  844. var reply = (buffer ?? string.Empty).Trim();
  845. SendTaskMessage($"{scanner.Name}Received:{reply}", MessageLevel.Info);
  846. // 只要有人在等扫码结果,就先完成等待(避免被下面 ExecuteAsync 干扰)
  847. var tcs = _scanTcs;
  848. if (tcs != null && !string.IsNullOrWhiteSpace(reply))
  849. {
  850. // 只完成一次
  851. tcs.TrySetResult(reply);
  852. }
  853. var _ = _remoteCommandService.ExecuteAsync(buffer, ScannerTCPCollection[scannerid].Token, async msg =>
  854. {
  855. try
  856. {
  857. if (scanner.ConnectType == TCPConnectType.Client)
  858. {
  859. if (scanner.IsConnected)
  860. {
  861. await scanner.SendAsync($"{msg}");
  862. }
  863. }
  864. else
  865. {
  866. var cient = (ITcpSessionClient)arg2;
  867. if (cient.Online)
  868. {
  869. await scanner.SendAsync(cient, $"{msg}");
  870. }
  871. }
  872. }
  873. catch (Exception ex)
  874. {
  875. LogHelper.WriteLogError("TCP发送数据时出错!", ex);
  876. SendTaskMessage(ex.Message, MessageLevel.Alarm);
  877. }
  878. });
  879. }
  880. catch (Exception ex)
  881. {
  882. LogHelper.WriteLogError("处理扫码枪接收的命令时出错!", ex);
  883. SendTaskMessage(ex.Message, MessageLevel.Alarm);
  884. }
  885. }
  886. #endregion
  887. #region 机器人&Feeder&相机连接状态事件
  888. /// <summary>
  889. /// 机器人发送事件
  890. /// </summary>
  891. /// <param name="arg1"></param>
  892. /// <param name="arg2"></param>
  893. /// <param name="arg3"></param>
  894. /// <exception cref="NotImplementedException"></exception>
  895. private void Management_SendEvent(Guid robotid, object arg2, string arg3)
  896. {
  897. var r = _robotService.GetRobot(robotid);
  898. SendTaskMessage($"{r.Name}Send:{arg3}", MessageLevel.Info);
  899. }
  900. /// <summary>
  901. /// 扫码枪发送事件
  902. /// </summary>
  903. /// <param name="arg1"></param>
  904. /// <param name="arg2"></param>
  905. /// <param name="arg3"></param>
  906. /// <exception cref="NotImplementedException"></exception>
  907. private void Management_ScannerSendEvent(Guid scannerid, object arg2, string arg3)
  908. {
  909. var r = _scannerService.GetScanner(scannerid);
  910. SendTaskMessage($"{r.Name}Send:{arg3}", MessageLevel.Info);
  911. }
  912. /// <summary>
  913. /// 机器人断开连接时
  914. /// </summary>
  915. /// <param name="arg1"></param>
  916. /// <param name="arg2"></param>
  917. /// <param name="arg3"></param>
  918. /// <exception cref="NotImplementedException"></exception>
  919. private void Management_DisconnectedEvent(Guid robotid, object arg2, ClosedEventArgs arg3)
  920. {
  921. if (RobotTCPCollection.ContainsKey(robotid))
  922. {
  923. RobotTCPCollection[robotid].Cancel();
  924. }
  925. var r = _configService.GetRobot(robotid);
  926. if (r.ConnectType == TCPConnectType.Server)
  927. {
  928. ITcpSessionClient socketClient = arg2 as ITcpSessionClient;
  929. SendTaskMessage($"{r.RobotName}[{socketClient.Id}:{socketClient.IP}]{Lang.断开连接}!", MessageLevel.Error);
  930. var robot = _robotService.GetRobot(robotid);
  931. if (robot.TcpService.Count < 1)
  932. {
  933. var sta = Status.FirstOrDefault(s => s.ID == robotid);
  934. App.Current.Dispatcher.BeginInvoke(new
  935. Action(() =>
  936. {
  937. sta.Message = $"{r.RobotName}{Lang.未连接}";
  938. sta.Background = new SolidColorBrush(Colors.Red);
  939. }));
  940. }
  941. }
  942. else
  943. {
  944. SendTaskMessage($"{r.RobotName}{Lang.断开连接}!", MessageLevel.Error);
  945. var sta = Status.FirstOrDefault(s => s.ID == robotid);
  946. App.Current.Dispatcher.BeginInvoke(new
  947. Action(() =>
  948. {
  949. sta.Message = $"{r.RobotName}{Lang.断开连接}";
  950. sta.Background = new SolidColorBrush(Colors.Red);
  951. }));
  952. }
  953. }
  954. /// <summary>
  955. /// 扫码枪断开连接时
  956. /// </summary>
  957. /// <param name="arg1"></param>
  958. /// <param name="arg2"></param>
  959. /// <param name="arg3"></param>
  960. /// <exception cref="NotImplementedException"></exception>
  961. private void Management_ScannerDisconnectedEvent(Guid scannerid, object arg2, ClosedEventArgs arg3)
  962. {
  963. if (ScannerTCPCollection.ContainsKey(scannerid))
  964. {
  965. ScannerTCPCollection[scannerid].Cancel();
  966. }
  967. var r = _configService.GetScanner(scannerid);
  968. if (r.ConnectType == TCPConnectType.Server)
  969. {
  970. ITcpSessionClient socketClient = arg2 as ITcpSessionClient;
  971. SendTaskMessage($"{r.ScannerName}[{socketClient.Id}:{socketClient.IP}]{Lang.断开连接}!", MessageLevel.Error);
  972. var scanner = _scannerService.GetScanner(scannerid);
  973. if (scanner.TcpService.Count < 1)
  974. {
  975. var sta = Status.FirstOrDefault(s => s.ID == scannerid);
  976. App.Current.Dispatcher.BeginInvoke(new
  977. Action(() =>
  978. {
  979. sta.Message = $"{r.ScannerName}{Lang.未连接}";
  980. sta.Background = new SolidColorBrush(Colors.Red);
  981. }));
  982. }
  983. }
  984. else
  985. {
  986. SendTaskMessage($"{r.ScannerName}{Lang.断开连接}!", MessageLevel.Error);
  987. var sta = Status.FirstOrDefault(s => s.ID == scannerid);
  988. App.Current.Dispatcher.BeginInvoke(new
  989. Action(() =>
  990. {
  991. sta.Message = $"{r.ScannerName}{Lang.断开连接}";
  992. sta.Background = new SolidColorBrush(Colors.Red);
  993. }));
  994. }
  995. }
  996. /// <summary>
  997. /// 机器人连接成功时
  998. /// </summary>
  999. /// <param name="arg1"></param>
  1000. /// <param name="arg2"></param>
  1001. /// <param name="arg3"></param>
  1002. /// <exception cref="NotImplementedException"></exception>
  1003. private void Management_ConnectedEvent(Guid robotid, object arg2, ConnectedEventArgs arg3)
  1004. {
  1005. var r = _configService.GetRobot(robotid);
  1006. if (r.ConnectType == TCPConnectType.Server)
  1007. {
  1008. ITcpSessionClient socketClient = arg2 as ITcpSessionClient;
  1009. SendTaskMessage($"{r.RobotName}[{socketClient.Id}:{socketClient.IP}]{Lang.已连接}!", MessageLevel.Debug);
  1010. var robot = _robotService.GetRobot(robotid);
  1011. if (robot.TcpService.Count > 0)
  1012. {
  1013. var sta = Status.FirstOrDefault(s => s.ID == robotid);
  1014. App.Current.Dispatcher.BeginInvoke(new
  1015. Action(() =>
  1016. {
  1017. sta.Message = $"{r.RobotName}{Lang.已连接}";
  1018. sta.Background = new SolidColorBrush(Colors.Green);
  1019. }));
  1020. }
  1021. }
  1022. else
  1023. {
  1024. SendTaskMessage($"{r.RobotName}{Lang.已连接}!", MessageLevel.Debug);
  1025. var sta = Status.FirstOrDefault(s => s.ID == robotid);
  1026. App.Current.Dispatcher.BeginInvoke(new
  1027. Action(() =>
  1028. {
  1029. sta.Message = $"{r.RobotName}{Lang.已连接}";
  1030. sta.Background = new SolidColorBrush(Colors.Green);
  1031. }));
  1032. }
  1033. }
  1034. /// <summary>
  1035. /// 扫码枪连接成功时
  1036. /// </summary>
  1037. /// <param name="arg1"></param>
  1038. /// <param name="arg2"></param>
  1039. /// <param name="arg3"></param>
  1040. /// <exception cref="NotImplementedException"></exception>
  1041. private void Management_ScannerConnectedEvent(Guid scannerid, object arg2, ConnectedEventArgs arg3)
  1042. {
  1043. var r = _configService.GetScanner(scannerid);
  1044. if (r.ConnectType == TCPConnectType.Server)
  1045. {
  1046. ITcpSessionClient socketClient = arg2 as ITcpSessionClient;
  1047. SendTaskMessage($"{r.ScannerName}[{socketClient.Id}:{socketClient.IP}]{Lang.已连接}!", MessageLevel.Debug);
  1048. var scanner = _scannerService.GetScanner(scannerid);
  1049. if (scanner.TcpService.Count > 0)
  1050. {
  1051. var sta = Status.FirstOrDefault(s => s.ID == scannerid);
  1052. App.Current.Dispatcher.BeginInvoke(new
  1053. Action(() =>
  1054. {
  1055. sta.Message = $"{r.ScannerName}{Lang.已连接}";
  1056. sta.Background = new SolidColorBrush(Colors.Green);
  1057. }));
  1058. }
  1059. }
  1060. else
  1061. {
  1062. SendTaskMessage($"{r.ScannerName}{Lang.已连接}!", MessageLevel.Debug);
  1063. var sta = Status.FirstOrDefault(s => s.ID == scannerid);
  1064. App.Current.Dispatcher.BeginInvoke(new
  1065. Action(() =>
  1066. {
  1067. sta.Message = $"{r.ScannerName}{Lang.已连接}";
  1068. sta.Background = new SolidColorBrush(Colors.Green);
  1069. }));
  1070. }
  1071. }
  1072. /// <summary>
  1073. /// Feeder连接状态改变时
  1074. /// </summary>
  1075. /// <param name="sender"></param>
  1076. /// <param name="state"></param>
  1077. private void Management_FeederConnectionStatusChanged(object sender, bool state)
  1078. {
  1079. IFeeder feeder = sender as IFeeder;
  1080. var sta = Status.FirstOrDefault(s => s.ID == feeder.Id);
  1081. if (state)
  1082. {
  1083. App.Current.Dispatcher.BeginInvoke(new
  1084. Action(() =>
  1085. {
  1086. sta.Message = $"{feeder.Name}{Lang.已连接}";
  1087. sta.Background = new SolidColorBrush(Colors.Green);
  1088. }));
  1089. SendTaskMessage($"{feeder.Name}{Lang.已连接}!", MessageLevel.Debug);
  1090. }
  1091. else
  1092. {
  1093. App.Current.Dispatcher.BeginInvoke(new
  1094. Action(() =>
  1095. {
  1096. sta.Message = $"{feeder.Name}{Lang.未连接}";
  1097. sta.Background = new SolidColorBrush(Colors.Red);
  1098. }));
  1099. SendTaskMessage($"{feeder.Name}{Lang.断开连接}!", MessageLevel.Error);
  1100. }
  1101. }
  1102. /// <summary>
  1103. /// 相机连接或者断开时
  1104. /// </summary>
  1105. /// <param name="id"></param>
  1106. /// <param name="state"></param>
  1107. private void Management_CameraConnectChangedEvent(Guid id, bool state)
  1108. {
  1109. var sta = Status.FirstOrDefault(s => s.ID == id);
  1110. var camera = _configService.GetCamera(id);
  1111. if (sta != null && camera != null)
  1112. {
  1113. if (state)
  1114. {
  1115. App.Current.Dispatcher.BeginInvoke(new Action(() =>
  1116. {
  1117. sta.Message = $"{camera.CameraName}{Lang.已连接}";
  1118. sta.Background = new SolidColorBrush(Colors.Green);
  1119. }));
  1120. }
  1121. else
  1122. {
  1123. App.Current.Dispatcher.BeginInvoke(new Action(() =>
  1124. {
  1125. sta.Message = $"{camera.CameraName}{Lang.断开连接}";
  1126. sta.Background = new SolidColorBrush(Colors.Red);
  1127. }));
  1128. }
  1129. }
  1130. }
  1131. /// <summary>
  1132. /// PLC连接状态改变事件
  1133. /// </summary>
  1134. /// <param name="plc"></param>
  1135. /// <param name="isconnected"></param>
  1136. private void Management_PlcConnectChangedEvent(object sender, bool isconnected)
  1137. {
  1138. IPlc plc = sender as IPlc;
  1139. var sta = Status.FirstOrDefault(s => s.ID == plc.Id);
  1140. if (plc.IsConnected)
  1141. {
  1142. SendTaskMessage($"{plc.Name}{Lang.已连接}!", MessageLevel.Debug);
  1143. if (sta == null) return;
  1144. App.Current.Dispatcher.BeginInvoke(new
  1145. Action(() =>
  1146. {
  1147. sta.Message = $"{plc.Name}{Lang.已连接}";
  1148. sta.Background = new SolidColorBrush(Colors.Green);
  1149. }));
  1150. }
  1151. else
  1152. {
  1153. SendTaskMessage($"{plc.Name}{Lang.断开连接}!", MessageLevel.Error);
  1154. if (sta == null) return;
  1155. App.Current.Dispatcher.BeginInvoke(new
  1156. Action(() =>
  1157. {
  1158. sta.Message = $"{plc.Name}{Lang.未连接}";
  1159. sta.Background = new SolidColorBrush(Colors.Red);
  1160. }));
  1161. }
  1162. }
  1163. /// <summary>
  1164. /// 电批连接状态改变时
  1165. /// </summary>
  1166. /// <param name="screwDevice"></param>
  1167. /// <param name="state"></param>
  1168. private void ScrewDriver_ConnectStateChangedEvent(object screwDevice, bool state)
  1169. {
  1170. try
  1171. {
  1172. XYD_ScrewDriver screwDriver = screwDevice as XYD_ScrewDriver;
  1173. if (state)
  1174. {
  1175. SendTaskMessage($"电批{Lang.已连接}!", MessageLevel.Debug);
  1176. var sta = Status.FirstOrDefault(s => s.ID == screwDriver.Id);
  1177. App.Current.Dispatcher.BeginInvoke(new
  1178. Action(() =>
  1179. {
  1180. sta.Message = $"电批{Lang.已连接}";
  1181. sta.Background = new SolidColorBrush(Colors.Green);
  1182. }));
  1183. }
  1184. else
  1185. {
  1186. SendTaskMessage($"电批{Lang.未连接}!", MessageLevel.Error);
  1187. var sta = Status.FirstOrDefault(s => s.ID == screwDriver.Id);
  1188. App.Current.Dispatcher.BeginInvoke(new
  1189. Action(() =>
  1190. {
  1191. sta.Message = $"电批{Lang.未连接}";
  1192. sta.Background = new SolidColorBrush(Colors.Red);
  1193. }));
  1194. }
  1195. }
  1196. catch (Exception ex)
  1197. {
  1198. LogHelper.WriteLogError("电批连接状态改变时出错了", ex);
  1199. }
  1200. }
  1201. #endregion
  1202. #region 后台服务器通讯事件
  1203. private void BgCommunicate_SendEvent(ITcpSessionClient client, string msg)
  1204. {
  1205. SendTaskMessage($"{Lang.服务器}[{client.ServicePort}] Send To {Lang.客户端}[{client.Id}:{client.IP}]:{msg}", MessageLevel.Info);
  1206. }
  1207. public Dictionary<string, CancellationTokenSource> BgCommunicateollection = new Dictionary<string, CancellationTokenSource>();
  1208. private async void BgCommunicate_ReceivedEvent(ITcpSessionClient client, string msg)
  1209. {
  1210. try
  1211. {
  1212. if (!BgCommunicateollection.ContainsKey(client.Id))
  1213. {
  1214. BgCommunicateollection.Add(client.Id, new CancellationTokenSource());
  1215. }
  1216. SendTaskMessage($"{Lang.服务器}[{client.ServicePort}]ReceiveFor{Lang.客户端}[{client.Id}:{client.IP}]:{msg}", MessageLevel.Info);
  1217. var _ = _remoteCommandService.ExecuteAsync(msg, BgCommunicateollection[client.Id].Token, async response =>
  1218. {
  1219. try
  1220. {
  1221. if (!client.Online)
  1222. {
  1223. return;
  1224. }
  1225. await BgCommunicate.SendAsync(client, $"{response}");
  1226. }
  1227. catch (Exception ex)
  1228. {
  1229. LogHelper.WriteLogError("后台TCP发送数据时出错!", ex);
  1230. SendTaskMessage(ex.Message, MessageLevel.Alarm);
  1231. }
  1232. });
  1233. }
  1234. catch (Exception ex)
  1235. {
  1236. LogHelper.WriteLogError("处理后台服务器接收的命令时出错!", ex);
  1237. SendTaskMessage(ex.Message, MessageLevel.Alarm);
  1238. }
  1239. }
  1240. private void BgCommunicate_DisconnectedEvent(ITcpSessionClient client, ClosedEventArgs e)
  1241. {
  1242. SendTaskMessage($"{Lang.服务器}[{client.ServicePort}]{Lang.客户端}[{client.Id}:{client.IP}]{Lang.断开连接}!", MessageLevel.Alarm);
  1243. if (BgCommunicateollection.ContainsKey(client.Id))
  1244. {
  1245. BgCommunicateollection[client.Id].Cancel();
  1246. }
  1247. }
  1248. private void BgCommunicate_ConnectedEvent(ITcpSessionClient client, ConnectedEventArgs e)
  1249. {
  1250. SendTaskMessage($"{Lang.服务器}[{client.ServicePort}]{Lang.客户端}[{client.Id}:{client.IP}]{Lang.连接成功}!", MessageLevel.Debug);
  1251. }
  1252. #endregion
  1253. #region PLC
  1254. /// <summary>
  1255. /// 将系统参数写入PLC
  1256. /// </summary>
  1257. /// <param name="systemConfiguration"></param>
  1258. /// <returns></returns>
  1259. public async Task WriteSystemParameterToPlcAsync(SystemConfiguration systemConfiguration)
  1260. {
  1261. var addressConfig = _configService.GetPlcAddresses();
  1262. var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
  1263. if (plc == null || !plc.IsConnected) return;
  1264. Dictionary<string, object> nodeValues = new Dictionary<string, object>();
  1265. nodeValues.Add(addressConfig.Out_WorkMode.Address, (Int16)systemConfiguration.WorkMode);
  1266. nodeValues.Add(addressConfig.Out_PickPointNum.Address, (Int16)systemConfiguration.PickPointNum);
  1267. nodeValues.Add(addressConfig.Out_DowmCameraNum.Address, (Int16)systemConfiguration.DowmCameraNum);
  1268. nodeValues.Add(addressConfig.Out_UpCameraPickNum.Address, (Int16)systemConfiguration.UpCameraPickNum);
  1269. nodeValues.Add(addressConfig.Out_UpCameraPutNum.Address, (Int16)systemConfiguration.UpCameraPutNum);
  1270. nodeValues.Add(addressConfig.Out_UPCameracheckNum.Address, (Int16)systemConfiguration.UPCameracheckNum);
  1271. nodeValues.Add(addressConfig.Out_FixedCameraPickNum.Address, (Int16)systemConfiguration.FixedCameraPickNum);
  1272. nodeValues.Add(addressConfig.Out_FixedCameraPutNum.Address, (Int16)systemConfiguration.FixedCameraPutNum);
  1273. nodeValues.Add(addressConfig.Out_FixedCameracheckNum.Address, (Int16)systemConfiguration.FixedCameracheckNum);
  1274. var res = await plc.WriteNodesAsync(nodeValues);
  1275. }
  1276. /// <summary>
  1277. /// 注册需要监控的PLC地址
  1278. /// </summary>
  1279. public void RegisterPlcMonitorAddress()
  1280. {
  1281. var addressConfig = _configService.GetPlcAddresses();
  1282. var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
  1283. if (plc == null || !plc.IsConnected) return;
  1284. //PLC地址数组
  1285. List<string> monitorNodeIds = new List<string>()
  1286. {
  1287. addressConfig.In_DowmCameraExe.Address,
  1288. addressConfig.In_UpCameraPickExe.Address,
  1289. addressConfig.In_UpCameraPutExe.Address,
  1290. addressConfig.In_UPCameracheckExe.Address,
  1291. addressConfig.In_FixedCameraPickExe.Address,
  1292. addressConfig.In_FixedCameraPutExe.Address,
  1293. addressConfig.In_FixedCameracheckExe.Address,
  1294. addressConfig.In_WorkStart.Address,
  1295. addressConfig.In_WorkDone.Address,
  1296. addressConfig.In_MesCheck.Address,
  1297. addressConfig.In_RequestPosition.Address,
  1298. addressConfig.AutoRunning.Address,
  1299. addressConfig.ManualMode.Address,
  1300. addressConfig.ClearMode.Address,
  1301. addressConfig.WorkCt.Address,
  1302. //addressConfig.WorkSpeed.Address,
  1303. };
  1304. for (int i = 0; i < 10; i++)
  1305. {
  1306. monitorNodeIds.Add(string.Format(addressConfig.In_MesCheck.Address, i));
  1307. }
  1308. //订阅PLC地址变化
  1309. //plc.SubscribeNodes("AutoSensor", monitorNodeIds, PlcCommandTrigger, OpcUaSubscriptionMode.CustomPolling);
  1310. // 1. 初始订阅(使用原生模式)
  1311. plc.SubscribeNodes("AutoSensor", monitorNodeIds, PlcCommandTrigger, OpcUaSubscriptionMode.CustomPolling);
  1312. // 2. 监听重连事件,重连成功后自动重新订阅
  1313. plc.ConnectChangedEvent -= Plc_ConnectChanged; // 防止重复注册
  1314. plc.ConnectChangedEvent += Plc_ConnectChanged;
  1315. // 定义重连处理方法(写在同一个类里即可)
  1316. void Plc_ConnectChanged(object sender, bool isConnected)
  1317. {
  1318. if (isConnected)
  1319. {
  1320. // 重连成功后,重新订阅节点
  1321. plc.SubscribeNodes("AutoSensor", monitorNodeIds, PlcCommandTrigger, OpcUaSubscriptionMode.CustomPolling);
  1322. }
  1323. }
  1324. }
  1325. /// <summary>
  1326. /// 写入点位信息给PLC
  1327. /// </summary>
  1328. /// <returns></returns>
  1329. public async Task WritePositionToPlcAsync()
  1330. {
  1331. var addressConfig = _configService.GetPlcAddresses();
  1332. var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
  1333. if (plc == null || !plc.IsConnected) return;
  1334. var current = _productService.GetCurrentProduct();
  1335. if (current == null) return;
  1336. if (current.PickCameraPoints != null && current.PickCameraPoints.Count > 0)
  1337. {
  1338. foreach (var item in current.PickCameraPoints)
  1339. {
  1340. await item.WriteToPlcAddress(addressConfig.Out_PickCamera, plc);
  1341. }
  1342. }
  1343. if (current.PickPoints != null && current.PickPoints.Count > 0)
  1344. {
  1345. foreach (var item in current.PickPoints)
  1346. {
  1347. await item.WriteToPlcAddress(addressConfig.Out_Pick, plc);
  1348. }
  1349. }
  1350. if (current.SecPosCameraPoints != null && current.SecPosCameraPoints.Count > 0)
  1351. {
  1352. foreach (var item in current.SecPosCameraPoints)
  1353. {
  1354. await item.WriteToPlcAddress(addressConfig.Out_SecPosCamera, plc);
  1355. }
  1356. }
  1357. if (current.ScrewCameraPoints != null && current.ScrewCameraPoints.Count > 0)
  1358. {
  1359. foreach (var item in current.ScrewCameraPoints)
  1360. {
  1361. await item.WriteToPlcAddress(addressConfig.Out_ScrewCamera, plc);
  1362. }
  1363. }
  1364. //if (current.ScrewPoints != null && current.ScrewPoints.Count > 0)
  1365. //{
  1366. // foreach (var item in current.ScrewPoints)
  1367. // {
  1368. // await item.WriteToPlcAddress(addressConfig.Out_Screw, plc);
  1369. // }
  1370. // await plc.WriteNodeAsync(addressConfig.Out_WorkNum.Address, (Int16)current.ScrewPoints.Count);
  1371. //}
  1372. if (current.CheckCameraPoints != null && current.CheckCameraPoints.Count > 0)
  1373. {
  1374. foreach (var item in current.CheckCameraPoints)
  1375. {
  1376. await item.WriteToPlcAddress(addressConfig.Out_CheckCamera, plc);
  1377. }
  1378. }
  1379. if (current.AoiPoints != null && current.AoiPoints.Count > 0)
  1380. {
  1381. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickNum.Address, (Int16)current.AoiPoints.Count);
  1382. foreach (var item in current.AoiPoints)
  1383. {
  1384. await item.WriteToPlcAddress(addressConfig.Out_AoiCamera, plc);
  1385. }
  1386. }
  1387. else
  1388. {
  1389. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickNum.Address, 0);
  1390. }
  1391. }
  1392. PointF[] DowmCameraResults = new PointF[10];
  1393. PointF[] UpCameraPutResults = new PointF[10];
  1394. bool _LastDowmCameraExe = false;
  1395. bool _LastScrewTeachExe = false;
  1396. bool _LastUpCameraPickExe = false;
  1397. bool _LastUpCameraPutExe = false;
  1398. bool _LastUPCameracheckExe = false;
  1399. bool _LastFixedCameraPickExe = false;
  1400. bool _LastFixedCameraPutExe = false;
  1401. bool _LastFixedCameracheckExe = false;
  1402. public bool _LastAutoRunning = false;
  1403. public bool _LastManualMode = false;
  1404. bool _LastFzCameracheckExe = false;
  1405. bool _LastClearMode = false;
  1406. bool _Lastworkct = false;
  1407. Int16 _Lastworkspeed = 0;
  1408. Int16 _LastWorkStart = 0;
  1409. Int16 _LastWorkDone = 0;
  1410. Int16 _LastRequestPosition = 0;
  1411. Int16[] _LastMesCheck = new Int16[10];
  1412. Int16 _LastPickINC = 0;
  1413. DateTime[] _LastMesCheckTime = new DateTime[10];
  1414. List<Task<(bool IsSucceed, bool[] Result, string Message)>> _PrcTaskList = new List<Task<(bool IsSucceed, bool[] Result, string Message)>>();
  1415. //List<Task<(bool IsSucceed, ICogImage[] Images, string Message, int cameraIndex, Guid procedureId)>> _ImageTaskList = new List<Task<(bool IsSucceed, ICogImage[] Images, string Message, int cameraIndex, Guid procedureId)>>();
  1416. private readonly object _stateLock = new object();
  1417. // private SharedSpeedFileHelper _speedFileHelper = new SharedSpeedFileHelper();
  1418. /// <summary>
  1419. /// PLC命令触发时 - 同步入口,立即释放OPC UA回调线程,实际逻辑异步执行
  1420. /// </summary>
  1421. /// <param name="tuple"></param>
  1422. private void PlcCommandTrigger((string key, string nodeId, object value) tuple)
  1423. {
  1424. // 立即释放OPC UA回调线程,避免阻塞Session导致后续WriteNodeAsync无法派发
  1425. //LogHelper.WriteLogInfo($"[PLC-TRACE] Trigger queued key={tuple.key}, node={tuple.nodeId}, value={tuple.value}, thread={Thread.CurrentThread.ManagedThreadId}, time={DateTime.Now:HH:mm:ss.fff}");
  1426. _ = Task.Run(async () =>
  1427. {
  1428. try
  1429. {
  1430. await PlcCommandTriggerAsync(tuple).ConfigureAwait(false);
  1431. }
  1432. catch (Exception ex)
  1433. {
  1434. LogHelper.WriteLogError($"PlcCommandTriggerAsync 执行异常, key={tuple.key}, node={tuple.nodeId}", ex);
  1435. }
  1436. });
  1437. }
  1438. /// <summary>
  1439. /// PLC命令触发时的异步处理逻辑
  1440. /// </summary>
  1441. private async Task PlcCommandTriggerAsync((string key, string nodeId, object value) tuple)
  1442. {
  1443. try
  1444. {
  1445. if (tuple.key != "AutoSensor")
  1446. {
  1447. return;
  1448. }
  1449. var addressConfig = _configService.GetPlcAddresses();
  1450. var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
  1451. if (plc == null || !plc.IsConnected) return;
  1452. // 获取当前产品
  1453. var currentProduct = _productService.GetCurrentProduct();
  1454. if (currentProduct == null)
  1455. {
  1456. return;
  1457. }
  1458. // 写入3D相机长度
  1459. if (addressConfig.In_UPCameracheckExe.Address.Contains(tuple.nodeId))
  1460. {
  1461. if (tuple.value is bool state)
  1462. {
  1463. if (_LastUPCameracheckExe != state)
  1464. {
  1465. _LastUPCameracheckExe = state;
  1466. }
  1467. else
  1468. {
  1469. return;
  1470. }
  1471. if (state)
  1472. {
  1473. //相机的编号
  1474. //Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_FixedCameracheckNum.Address);
  1475. // 读取相机编号
  1476. Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_FixedCameracheckNum.Address);
  1477. SendTaskMessage($"写入3D相机长度...编号:{cameraIndex}", MessageLevel.Debug);
  1478. // 找到对应编号的 PlcPoint
  1479. var targetPoint = currentProduct.AoiPoints?.FirstOrDefault(p => p.Number == cameraIndex);
  1480. if (targetPoint == null)
  1481. {
  1482. SendTaskMessage($"未找到 AOI 点位,编号:{cameraIndex}", MessageLevel.Alarm);
  1483. await plc.WriteNodeAsync(addressConfig.Out_UPCameracheckStatus.Address, (Int16)2);
  1484. return;
  1485. }
  1486. SetProducts(new int[] { targetPoint.Camera_Product1, targetPoint.Camera_Product2, targetPoint.Camera_Product3, targetPoint.Camera_Product4 });
  1487. SetBatchPoints(new int[] { targetPoint.Camera_Data1, targetPoint.Camera_Data2, targetPoint.Camera_Data3, targetPoint.Camera_Data4 });
  1488. await plc.WriteNodeAsync(addressConfig.Out_UPCameracheckStatus.Address, (Int16)1);
  1489. }
  1490. else
  1491. {
  1492. SendTaskMessage($"写入3D相机长度信号已关闭", MessageLevel.Alarm);
  1493. await plc.WriteNodeAsync(addressConfig.Out_UPCameracheckStatus.Address, (Int16)0);
  1494. }
  1495. }
  1496. }
  1497. // 发送点位个数
  1498. else if (addressConfig.In_RequestPosition.Address.Contains(tuple.nodeId))
  1499. {
  1500. if (tuple.value is Int16 state)
  1501. {
  1502. if (_LastRequestPosition != state)
  1503. {
  1504. _LastRequestPosition = state;
  1505. }
  1506. else
  1507. {
  1508. return;
  1509. }
  1510. if (state == 1)
  1511. {
  1512. var current = _productService.GetCurrentProduct();
  1513. if (current == null) return;
  1514. await plc.WriteNodeAsync(addressConfig.Out_CameraDone.Address, (Int16)1);
  1515. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickNum.Address, (Int16)current.AoiPoints.Count);
  1516. }
  1517. else
  1518. {
  1519. SendTaskMessage($"多相机坐标合并请求已结束或被取消,state={state}", MessageLevel.Alarm);
  1520. await plc.WriteNodeAsync(addressConfig.Out_CameraDone.Address, (Int16)0);
  1521. }
  1522. }
  1523. }
  1524. // 固定相机检测拍照
  1525. else if (addressConfig.In_FixedCameracheckExe.Address.Contains(tuple.nodeId))
  1526. {
  1527. if (tuple.value is bool state)
  1528. {
  1529. if (_LastFixedCameracheckExe != state)
  1530. {
  1531. _LastFixedCameracheckExe = state;
  1532. }
  1533. else
  1534. {
  1535. return;
  1536. }
  1537. if (state)
  1538. {
  1539. LockResult lockResult = new LockResult();
  1540. lockResult.TimeStart = DateTime.Now;
  1541. // 读取相机编号
  1542. Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_FixedCameracheckNum.Address);
  1543. SendTaskMessage($"触发固定相机检测拍照...编号:{cameraIndex}", MessageLevel.Debug);
  1544. // 找到对应编号的 PlcPoint
  1545. var targetPoint = currentProduct.AoiPoints?.FirstOrDefault(p => p.Number == cameraIndex);
  1546. if (targetPoint == null)
  1547. {
  1548. SendTaskMessage($"未找到 AOI 点位,编号:{cameraIndex}", MessageLevel.Alarm);
  1549. await plc.WriteNodeAsync(addressConfig.Out_FixedCameracheckStatus.Address, (Int16)2);
  1550. return;
  1551. }
  1552. // 收集要执行的流程 id(仅添加大于0的)
  1553. var procIds = new List<Guid>();
  1554. try
  1555. {
  1556. if (targetPoint.CameraProcedureId1 != Guid.Empty && !procIds.Contains(targetPoint.CameraProcedureId1)) procIds.Add(targetPoint.CameraProcedureId1);
  1557. if (targetPoint.CameraProcedureId2 != Guid.Empty && !procIds.Contains(targetPoint.CameraProcedureId2)) procIds.Add(targetPoint.CameraProcedureId2);
  1558. if (targetPoint.CameraProcedureId3 != Guid.Empty && !procIds.Contains(targetPoint.CameraProcedureId3)) procIds.Add(targetPoint.CameraProcedureId3);
  1559. if (targetPoint.CameraProcedureId4 != Guid.Empty && !procIds.Contains(targetPoint.CameraProcedureId4)) procIds.Add(targetPoint.CameraProcedureId4);
  1560. if (targetPoint.CameraProcedureId5 != Guid.Empty && !procIds.Contains(targetPoint.CameraProcedureId5)) procIds.Add(targetPoint.CameraProcedureId5);
  1561. if (targetPoint.CameraProcedureId6 != Guid.Empty && !procIds.Contains(targetPoint.CameraProcedureId6)) procIds.Add(targetPoint.CameraProcedureId6);
  1562. if (targetPoint.CameraProcedureId7 != Guid.Empty && !procIds.Contains(targetPoint.CameraProcedureId7)) procIds.Add(targetPoint.CameraProcedureId7);
  1563. if (targetPoint.CameraProcedureId8 != Guid.Empty && !procIds.Contains(targetPoint.CameraProcedureId8)) procIds.Add(targetPoint.CameraProcedureId8);
  1564. }
  1565. catch { }
  1566. var sysConfig = _configService.GetSystemConfiguration();
  1567. #region 扫码枪扫码
  1568. if (sysConfig.ScannerUse == true && cameraIndex == 1 && sysConfig.CodeUse2 == true)
  1569. {
  1570. ScanValue = "";
  1571. _scanDoneEvent.Reset(); // 重要:先关门
  1572. await Scan_Client.SendAsync("T");
  1573. // 等待扫码结果,最多 3 秒
  1574. bool scanOk = await Task.Run(() => _scanDoneEvent.Wait(3000));
  1575. if (!scanOk || ScanValue.IsNullOrWhiteSpace())
  1576. {
  1577. SendTaskMessage("二维码拍照失败或超时", MessageLevel.Alarm);
  1578. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (short)3);
  1579. return;
  1580. }
  1581. code = ScanValue;
  1582. SendTaskMessage($"扫码成功,SN:{code}", MessageLevel.Info);
  1583. //这里缺少从MES获取产品配方的内容,需要补充
  1584. _LastMesCheckTime[0] = (await _mesService.GetServerTimeAsync(code, 2)).Now;
  1585. //_LastMesCheckTime[1] = DateTime.Now;
  1586. LogHelper.WriteLogMes($"【mes开始QUERY】");
  1587. SendTaskMessage($"mes开始QUERY", MessageLevel.Info);
  1588. (bool isSuccess, string response) = await _mesService.StationGetAsync(code, "", 2);//询问mes
  1589. if (isSuccess)
  1590. {
  1591. //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
  1592. LogHelper.WriteLogMes($"询问mes成功");
  1593. SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
  1594. if (response != "MES功能未启用!")
  1595. {
  1596. string[] items = response.Split('\n');
  1597. string snItem = items.FirstOrDefault(f => f.Contains("sn="));
  1598. if (snItem != null)
  1599. {
  1600. ProductMainSN = snItem.Replace("sn=", "").Trim();
  1601. _productService.CurrentProductCode = ProductMainSN;
  1602. SendTaskMessage($"产品主sn:{ProductMainSN}", MessageLevel.Info);
  1603. }
  1604. string woItem = items.FirstOrDefault(f => f.Contains("wo="));
  1605. if (woItem != null)
  1606. {
  1607. wo[0] = woItem.Replace("wo=", "").Trim();
  1608. SendTaskMessage($"产品wo:{wo}", MessageLevel.Info);
  1609. }
  1610. string modelItem = items.FirstOrDefault(f => f.Contains("model_num="));
  1611. if (modelItem != null)
  1612. {
  1613. model_num[0] = modelItem.Replace("model_num=", "").Trim();
  1614. SendTaskMessage($"model_num:{model_num}", MessageLevel.Info);
  1615. }
  1616. string colorItem = items.FirstOrDefault(f => f.Contains("color="));
  1617. if (colorItem != null)
  1618. {
  1619. color[0] = colorItem.Replace("color=", "").Trim();
  1620. SendTaskMessage($"color:{color}", MessageLevel.Info);
  1621. }
  1622. string ppidItem = items.FirstOrDefault(f => f.Contains("ppid="));
  1623. if (ppidItem != null)
  1624. {
  1625. ppid[0] = ppidItem.Replace("ppid=", "").Trim();
  1626. SendTaskMessage($"ppid:{ppid}", MessageLevel.Info);
  1627. }
  1628. string stageItem = items.FirstOrDefault(f => f.Contains("stage="));
  1629. if (stageItem != null)
  1630. {
  1631. stage[0] = stageItem.Replace("stage=", "").Trim();
  1632. SendTaskMessage($"stage:{stage[0]}", MessageLevel.Info);
  1633. }
  1634. string kbsnitem = items.FirstOrDefault(f => f.Contains("KB="));
  1635. if (kbsnitem != null)
  1636. {
  1637. kb_sn[0] = kbsnitem.Replace("KB=", "").Trim();
  1638. SendTaskMessage($"KB:{kb_sn}", MessageLevel.Info);
  1639. }
  1640. string kbpnsnitem = items.FirstOrDefault(f => f.Contains("KB_PN="));
  1641. if (kbpnsnitem != null)
  1642. {
  1643. kb_pn[0] = kbpnsnitem.Replace("KB_PN=", "").Trim();
  1644. SendTaskMessage($"KB_PN:{kb_pn[0]}", MessageLevel.Info);
  1645. }
  1646. FinalResultStatus = "检测中";
  1647. FinalResultText = "检测中";
  1648. var item1 = await _systemDatabaseService.QueryProductWithMesALLAsync();
  1649. foreach (var q in item1)
  1650. {
  1651. if (!string.IsNullOrEmpty(q.ProductName))
  1652. {
  1653. ProductWithMes productWithMes = new ProductWithMes();
  1654. ProductList = new ObservableCollection<ProductModel>(_productService.GetAllProducts());
  1655. Guid productId = Guid.Empty;
  1656. foreach (var itt in ProductList)
  1657. {
  1658. if (itt.Name == q.ProductName)
  1659. {
  1660. productId = itt.ID;
  1661. break;
  1662. }
  1663. }
  1664. if (_configService.GetSystemConfiguration().IsTP_AOI)
  1665. {
  1666. if (currentProduct.ID != productId && q.ProductLoad.Contains(kb_pn[0]))
  1667. {
  1668. //切换产品
  1669. SendTaskMessage($"开始切换产品{q.ProductName}", MessageLevel.Error);
  1670. var _ = Application.Current.Dispatcher.BeginInvoke(new Action(() => { _dialogService.ShowDialog("UProgressBar", rst => { }); }));
  1671. await Task.Delay(50);
  1672. _ = App.Current.Dispatcher.BeginInvoke(new Action(() =>
  1673. {
  1674. _eventAggregator.GetEvent<ProgressNotification>().Publish(new UProgressBar.ProgressParameter { Maximum = 2, Minimum = 0, SubTitle = $"切换产品...", Message = $"切换{q.ProductName}产品中...", Value = 0 });
  1675. }));
  1676. await _productService.LoadProductAsync(productId);
  1677. _productService.SetCurrentProduct(productId);
  1678. await WritePositionToPlcAsync();
  1679. _ = App.Current.Dispatcher.BeginInvoke(new Action(() =>
  1680. {
  1681. _eventAggregator.GetEvent<ProgressNotification>().Publish(new UProgressBar.ProgressParameter { Maximum = 2, Minimum = 0, SubTitle = $"切换产品...", Message = $"{Lang.完成}", Value = -1 });
  1682. }));
  1683. SendTaskMessage($"切换产品成功", MessageLevel.Debug);
  1684. break;
  1685. }
  1686. }
  1687. else
  1688. {
  1689. if (currentProduct.ID != productId && model_num[0].Contains(q.ProductCode))
  1690. {
  1691. //切换产品
  1692. SendTaskMessage($"开始切换产品{q.ProductCode}", MessageLevel.Error);
  1693. var _ = Application.Current.Dispatcher.BeginInvoke(new Action(() => { _dialogService.ShowDialog("UProgressBar", rst => { }); }));
  1694. await Task.Delay(50);
  1695. _ = App.Current.Dispatcher.BeginInvoke(new Action(() =>
  1696. {
  1697. _eventAggregator.GetEvent<ProgressNotification>().Publish(new UProgressBar.ProgressParameter { Maximum = 2, Minimum = 0, SubTitle = $"切换产品...", Message = $"切换{q.ProductName}产品中...", Value = 0 });
  1698. }));
  1699. await _productService.LoadProductAsync(productId);
  1700. _productService.SetCurrentProduct(productId);
  1701. await WritePositionToPlcAsync();
  1702. _ = App.Current.Dispatcher.BeginInvoke(new Action(() =>
  1703. {
  1704. _eventAggregator.GetEvent<ProgressNotification>().Publish(new UProgressBar.ProgressParameter { Maximum = 2, Minimum = 0, SubTitle = $"切换产品...", Message = $"{Lang.完成}", Value = -1 });
  1705. }));
  1706. SendTaskMessage($"切换产品成功", MessageLevel.Debug);
  1707. break;
  1708. }
  1709. }
  1710. }
  1711. }
  1712. }
  1713. LogHelper.WriteLogMes($"【mes结束QUERY】");
  1714. SendTaskMessage($"mes结束QUERY", MessageLevel.Info);
  1715. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)1);
  1716. return;
  1717. }
  1718. else
  1719. {
  1720. //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
  1721. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)3);
  1722. LogHelper.WriteLogMes($"询问mes失败");
  1723. SendTaskMessage($"询问mes失败:{response}", MessageLevel.Error);
  1724. return;
  1725. }
  1726. }
  1727. if (sysConfig.ScannerUse == true && cameraIndex == 1 && sysConfig.CodeUse == true)
  1728. {
  1729. ScanValue = "";
  1730. _scanDoneEvent.Reset(); // 重要:先关门
  1731. await Scan_Client.SendAsync("T");
  1732. // 等待扫码结果,最多 3 秒
  1733. bool scanOk = await Task.Run(() => _scanDoneEvent.Wait(3000));
  1734. if (!scanOk || ScanValue.IsNullOrWhiteSpace())
  1735. {
  1736. SendTaskMessage("二维码拍照失败或超时", MessageLevel.Alarm);
  1737. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (short)3);
  1738. return;
  1739. }
  1740. code = ScanValue;
  1741. SendTaskMessage($"扫码成功,SN:{code}", MessageLevel.Info);
  1742. //这里缺少从MES获取产品配方的内容,需要补充
  1743. _LastMesCheckTime[0] = (await _mesService.GetServerTimeAsync(code, 2)).Now;
  1744. LogHelper.WriteLogMes($"【mes开始QUERY】");
  1745. SendTaskMessage($"mes开始QUERY", MessageLevel.Info);
  1746. //(bool isSuccess, string response) = await _mesService.StationGetAsync(code, "", 2);//询问mes
  1747. (bool isSuccess, string response) = await _mesService.StationGetExAsync(code, "", 2);//基于电池的SN获取产品SN,询问mes
  1748. if (isSuccess)
  1749. {
  1750. //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
  1751. string ProductMainSN_Temp = "";
  1752. LogHelper.WriteLogMes($"询问mes成功");
  1753. SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
  1754. if (response != "MES功能未启用!")
  1755. {
  1756. string[] item = response.Split('\n');
  1757. string snItem = item.FirstOrDefault(f => f.Contains("sn="));
  1758. if (snItem != null)
  1759. {
  1760. ProductMainSN_Temp = snItem.Replace("sn=", "").Trim();
  1761. SendTaskMessage($"sn:{ProductMainSN_Temp}", MessageLevel.Info);
  1762. }
  1763. }
  1764. LogHelper.WriteLogMes($"询问mes成功");
  1765. SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
  1766. //20260214,特别版(电池组装)
  1767. (bool isSuccess2, string response2) = await _mesService.StationGetAsync(ProductMainSN_Temp, "", 2);//询问mes
  1768. if (isSuccess2)
  1769. {
  1770. LogHelper.WriteLogMes($"询问mes成功");
  1771. SendTaskMessage($"询问mes成功:{response2}", MessageLevel.Debug);
  1772. if (response2 != "MES功能未启用!")
  1773. {
  1774. string[] item = response2.Split('\n');
  1775. string snItem = item.FirstOrDefault(f => f.Contains("sn="));
  1776. if (snItem != null)
  1777. {
  1778. ProductMainSN = snItem.Replace("sn=", "").Trim();
  1779. _productService.CurrentProductCode = ProductMainSN;
  1780. SendTaskMessage($"产品主sn:{ProductMainSN}", MessageLevel.Info);
  1781. }
  1782. string woItem = item.FirstOrDefault(f => f.Contains("wo="));
  1783. if (woItem != null)
  1784. {
  1785. wo[0] = woItem.Replace("wo=", "").Trim();
  1786. SendTaskMessage($"产品wo:{wo[0]}", MessageLevel.Info);
  1787. }
  1788. string modelItem = item.FirstOrDefault(f => f.Contains("model_num="));
  1789. if (modelItem != null)
  1790. {
  1791. model_num[0] = modelItem.Replace("model_num=", "").Trim();
  1792. SendTaskMessage($"model_num:{model_num[0]}", MessageLevel.Info);
  1793. }
  1794. string colorItem = item.FirstOrDefault(f => f.Contains("color="));
  1795. if (colorItem != null)
  1796. {
  1797. color[0] = colorItem.Replace("color=", "").Trim();
  1798. SendTaskMessage($"color:{color[0]}", MessageLevel.Info);
  1799. }
  1800. string ppidItem = item.FirstOrDefault(f => f.Contains("ppid="));
  1801. if (ppidItem != null)
  1802. {
  1803. ppid[0] = ppidItem.Replace("ppid=", "").Trim();
  1804. SendTaskMessage($"ppid:{ppid[0]}", MessageLevel.Info);
  1805. }
  1806. string stageItem = item.FirstOrDefault(f => f.Contains("stage="));
  1807. if (stageItem != null)
  1808. {
  1809. stage[0] = stageItem.Replace("stage=", "").Trim();
  1810. SendTaskMessage($"stage:{stage[0]}", MessageLevel.Info);
  1811. }
  1812. string kbsnitem = item.FirstOrDefault(f => f.Contains("KB="));
  1813. if (kbsnitem != null)
  1814. {
  1815. kb_sn[0] = kbsnitem.Replace("KB=", "").Trim();
  1816. SendTaskMessage($"KB:{kb_sn[0]}", MessageLevel.Info);
  1817. }
  1818. string kbpnsnitem = item.FirstOrDefault(f => f.Contains("KB_PN="));
  1819. if (kbpnsnitem != null)
  1820. {
  1821. kb_pn[0] = kbpnsnitem.Replace("KB_PN=", "").Trim();
  1822. SendTaskMessage($"KB_PN:{kb_pn[0]}", MessageLevel.Info);
  1823. }
  1824. FinalResultStatus = "检测中";
  1825. FinalResultText = "检测中";
  1826. var item1 = await _systemDatabaseService.QueryProductWithMesALLAsync();
  1827. foreach (var q in item1)
  1828. {
  1829. if (!string.IsNullOrEmpty(q.ProductName))
  1830. {
  1831. ProductWithMes productWithMes = new ProductWithMes();
  1832. ProductList = new ObservableCollection<ProductModel>(_productService.GetAllProducts());
  1833. Guid productId = Guid.Empty;
  1834. foreach (var itt in ProductList)
  1835. {
  1836. if (itt.Name == q.ProductName)
  1837. {
  1838. productId = itt.ID;
  1839. break;
  1840. }
  1841. }
  1842. if (_configService.GetSystemConfiguration().IsTP_AOI)
  1843. {
  1844. if (currentProduct.ID != productId && q.ProductLoad.Contains(kb_pn[0]))
  1845. {
  1846. //切换产品
  1847. SendTaskMessage($"开始切换产品{q.ProductName}", MessageLevel.Error);
  1848. var _ = Application.Current.Dispatcher.BeginInvoke(new Action(() => { _dialogService.ShowDialog("UProgressBar", rst => { }); }));
  1849. await Task.Delay(50);
  1850. _ = App.Current.Dispatcher.BeginInvoke(new Action(() =>
  1851. {
  1852. _eventAggregator.GetEvent<ProgressNotification>().Publish(new UProgressBar.ProgressParameter { Maximum = 2, Minimum = 0, SubTitle = $"切换产品...", Message = $"切换{q.ProductName}产品中...", Value = 0 });
  1853. }));
  1854. await _productService.LoadProductAsync(productId);
  1855. _productService.SetCurrentProduct(productId);
  1856. await WritePositionToPlcAsync();
  1857. _ = App.Current.Dispatcher.BeginInvoke(new Action(() =>
  1858. {
  1859. _eventAggregator.GetEvent<ProgressNotification>().Publish(new UProgressBar.ProgressParameter { Maximum = 2, Minimum = 0, SubTitle = $"切换产品...", Message = $"{Lang.完成}", Value = -1 });
  1860. }));
  1861. SendTaskMessage($"切换产品成功", MessageLevel.Debug);
  1862. break;
  1863. }
  1864. }
  1865. else
  1866. {
  1867. if (currentProduct.ID != productId && model_num[0].Contains(q.ProductCode))
  1868. {
  1869. //切换产品
  1870. SendTaskMessage($"开始切换产品{q.ProductCode}", MessageLevel.Error);
  1871. var _ = Application.Current.Dispatcher.BeginInvoke(new Action(() => { _dialogService.ShowDialog("UProgressBar", rst => { }); }));
  1872. await Task.Delay(50);
  1873. _ = App.Current.Dispatcher.BeginInvoke(new Action(() =>
  1874. {
  1875. _eventAggregator.GetEvent<ProgressNotification>().Publish(new UProgressBar.ProgressParameter { Maximum = 2, Minimum = 0, SubTitle = $"切换产品...", Message = $"切换{q.ProductName}产品中...", Value = 0 });
  1876. }));
  1877. await _productService.LoadProductAsync(productId);
  1878. _productService.SetCurrentProduct(productId);
  1879. await WritePositionToPlcAsync();
  1880. _ = App.Current.Dispatcher.BeginInvoke(new Action(() =>
  1881. {
  1882. _eventAggregator.GetEvent<ProgressNotification>().Publish(new UProgressBar.ProgressParameter { Maximum = 2, Minimum = 0, SubTitle = $"切换产品...", Message = $"{Lang.完成}", Value = -1 });
  1883. }));
  1884. SendTaskMessage($"切换产品成功", MessageLevel.Debug);
  1885. break;
  1886. }
  1887. }
  1888. }
  1889. }
  1890. }
  1891. LogHelper.WriteLogMes($"第二次询问mes成功");
  1892. SendTaskMessage($"第二次询问mes成功:{response2}", MessageLevel.Debug);
  1893. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)1);
  1894. }
  1895. else
  1896. {
  1897. LogHelper.WriteLogMes($"第二次询问mes失败");
  1898. SendTaskMessage($"第二次询问mes失败:{response2}", MessageLevel.Error);
  1899. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)3);
  1900. string[] item = response2.Split('\n');
  1901. string snItem = item.FirstOrDefault(f => f.Contains("sn="));
  1902. if (snItem != null)
  1903. {
  1904. ProductMainSN = snItem.Replace("sn=", "").Trim();
  1905. _productService.CurrentProductCode = ProductMainSN;
  1906. await plc.WriteNodeAsync<string>(string.Format(addressConfig.In_Code.Address, 0), ProductMainSN);
  1907. SendTaskMessage($"产品主sn:{ProductMainSN}", MessageLevel.Info);
  1908. }
  1909. }
  1910. }
  1911. else
  1912. {
  1913. //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
  1914. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)3);
  1915. LogHelper.WriteLogMes($"询问mes失败");
  1916. SendTaskMessage($"询问mes失败:{response}", MessageLevel.Error);
  1917. }
  1918. return;
  1919. }
  1920. #endregion
  1921. if (procIds.Count == 0 && cameraIndex != currentProduct.PhotoCountStop)
  1922. {
  1923. SendTaskMessage($"Point#{cameraIndex} 未配置任何视觉流程 (CameraProcedureId1/2/3)", MessageLevel.Alarm);
  1924. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)2);
  1925. return;
  1926. }
  1927. var cameraProcedures = currentProduct.CameraProcedures;
  1928. if (cameraProcedures == null || cameraProcedures.Count == 0)
  1929. {
  1930. if (cameraIndex != currentProduct.PhotoCountStop)
  1931. {
  1932. SendTaskMessage($"当前产品未配置 CameraProcedures,无法执行视觉流程", MessageLevel.Alarm);
  1933. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)2);
  1934. return;
  1935. }
  1936. }
  1937. if (cameraIndex == currentProduct.PhotoCount)
  1938. {
  1939. //_PrcTaskList.Clear();
  1940. AllResult = new ConcurrentBag<bool>();
  1941. lockResultsAll = new ConcurrentBag<LockResult>();
  1942. int count = 0;
  1943. int isscan = 0;
  1944. var AllProcId = new List<Guid>();
  1945. foreach (var item in currentProduct.AoiPoints)
  1946. {
  1947. if (item.Enable_Start_Node == 1)
  1948. {
  1949. #region 判断执行视觉模板个数
  1950. if (item.Label == "扫码")
  1951. {
  1952. isscan = -1;
  1953. }
  1954. if (item.CameraProcedureId1 != Guid.Empty && !AllProcId.Contains(item.CameraProcedureId1)) AllProcId.Add(item.CameraProcedureId1);
  1955. if (item.CameraProcedureId2 != Guid.Empty && !AllProcId.Contains(item.CameraProcedureId2)) AllProcId.Add(item.CameraProcedureId2);
  1956. if (item.CameraProcedureId3 != Guid.Empty && !AllProcId.Contains(item.CameraProcedureId3)) AllProcId.Add(item.CameraProcedureId3);
  1957. if (item.CameraProcedureId4 != Guid.Empty && !AllProcId.Contains(item.CameraProcedureId4)) AllProcId.Add(item.CameraProcedureId4);
  1958. if (item.CameraProcedureId5 != Guid.Empty && !AllProcId.Contains(item.CameraProcedureId5)) AllProcId.Add(item.CameraProcedureId5);
  1959. if (item.CameraProcedureId6 != Guid.Empty && !AllProcId.Contains(item.CameraProcedureId6)) AllProcId.Add(item.CameraProcedureId6);
  1960. if (item.CameraProcedureId7 != Guid.Empty && !AllProcId.Contains(item.CameraProcedureId7)) AllProcId.Add(item.CameraProcedureId7);
  1961. if (item.CameraProcedureId8 != Guid.Empty && !AllProcId.Contains(item.CameraProcedureId8)) AllProcId.Add(item.CameraProcedureId8);
  1962. #endregion
  1963. }
  1964. }
  1965. count = AllProcId.Count + isscan;
  1966. countdown = new CountdownEvent(count);
  1967. //SendTaskMessage($"需要执行模板数:{count}", MessageLevel.Alarm);
  1968. LogHelper.WriteLogInfo($"需要执行模板数:{count}");
  1969. _ = App.Current.Dispatcher.BeginInvoke(new Action(() =>
  1970. {
  1971. _eventAggregator.GetEvent<LockResetNotification>().Publish();
  1972. }));
  1973. }
  1974. #region 相机扫码
  1975. if (sysConfig.CodeUse == true && cameraIndex == 1)
  1976. {
  1977. var cts = new CancellationTokenSource();
  1978. // CameraProcedureId 存储的是具体的视觉流程 Id(ProcedureModel.Id),
  1979. // 需要在所有 CameraProcedures 的 ProcedureModels 中查找匹配的流程。
  1980. ProcedureModel selectedProcedure = null;
  1981. try
  1982. {
  1983. cameraProcedures = currentProduct.CameraProcedures;
  1984. if (cameraProcedures != null)
  1985. {
  1986. foreach (var cp in cameraProcedures)
  1987. {
  1988. if (cp?.ProcedureModels == null) continue;
  1989. selectedProcedure = cp.ProcedureModels.FirstOrDefault(pm => pm.Id == targetPoint.CameraProcedureId1);
  1990. if (selectedProcedure != null) break;
  1991. }
  1992. }
  1993. }
  1994. catch (Exception ex)
  1995. {
  1996. LogHelper.WriteLogError("查找 AOI 点位对应视觉流程时出错", ex);
  1997. }
  1998. if (selectedProcedure == null)
  1999. {
  2000. SendTaskMessage($"未找到 AOI 点位对应的视觉流程,Point#{cameraIndex} ProcedureId={targetPoint.CameraProcedureId1}", MessageLevel.Alarm);
  2001. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)2);
  2002. return;
  2003. }
  2004. if (selectedProcedure.Id == currentProduct.FixedDownCameraProcedureId && sysConfig.TurnOnAllLightUse == true)
  2005. {
  2006. await _remoteCommandService.SetLightBeforePhoto(selectedProcedure);
  2007. }
  2008. var visionResult = await _remoteCommandService.ExecutePhotoGetSinglePoint2(selectedProcedure, null, null, cts.Token);
  2009. if (visionResult.IsSucceed)
  2010. {
  2011. code = visionResult.X.ToUpper();
  2012. SendTaskMessage($"扫码成功,SN:{code}", MessageLevel.Info);
  2013. //这里缺少从MES获取产品配方的内容,需要补充
  2014. _LastMesCheckTime[0] = (await _mesService.GetServerTimeAsync(code, 2)).Now;
  2015. LogHelper.WriteLogMes($"【mes开始QUERY】");
  2016. SendTaskMessage($"mes开始QUERY", MessageLevel.Info);
  2017. //(bool isSuccess, string response) = await _mesService.StationGetAsync(code, "", 2);//询问mes
  2018. (bool isSuccess, string response) = await _mesService.StationGetExAsync(code, "", 2);
  2019. if (isSuccess)
  2020. {
  2021. //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
  2022. string ProductMainSN_Temp = "";
  2023. LogHelper.WriteLogMes($"询问mes成功");
  2024. SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
  2025. if (response != "MES功能未启用!")
  2026. {
  2027. string[] item = response.Split('\n');
  2028. string snItem = item.FirstOrDefault(f => f.Contains("sn="));
  2029. if (snItem != null)
  2030. {
  2031. ProductMainSN_Temp = snItem.Replace("sn=", "").Trim();
  2032. SendTaskMessage($"sn:{ProductMainSN_Temp}", MessageLevel.Info);
  2033. }
  2034. }
  2035. LogHelper.WriteLogMes($"询问mes成功");
  2036. SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
  2037. //20260214,特别版(电池组装)
  2038. (bool isSuccess2, string response2) = await _mesService.StationGetAsync(ProductMainSN_Temp, "", 2);//询问mes
  2039. if (isSuccess2)
  2040. {
  2041. LogHelper.WriteLogMes($"询问mes成功");
  2042. SendTaskMessage($"询问mes成功:{response2}", MessageLevel.Debug);
  2043. if (response2 != "MES功能未启用!")
  2044. {
  2045. string[] item = response2.Split('\n');
  2046. string snItem = item.FirstOrDefault(f => f.Contains("sn="));
  2047. if (snItem != null)
  2048. {
  2049. ProductMainSN = snItem.Replace("sn=", "").Trim();
  2050. _productService.CurrentProductCode = ProductMainSN;
  2051. await plc.WriteNodeAsync<string>(string.Format(addressConfig.In_Code.Address, 0), ProductMainSN);
  2052. SendTaskMessage($"产品主sn:{ProductMainSN}", MessageLevel.Info);
  2053. }
  2054. string woItem = item.FirstOrDefault(f => f.Contains("wo="));
  2055. if (woItem != null)
  2056. {
  2057. wo[0] = woItem.Replace("wo=", "").Trim();
  2058. SendTaskMessage($"产品wo:{wo[0]}", MessageLevel.Info);
  2059. }
  2060. string modelItem = item.FirstOrDefault(f => f.Contains("model_num="));
  2061. if (modelItem != null)
  2062. {
  2063. model_num[0] = modelItem.Replace("model_num=", "").Trim();
  2064. SendTaskMessage($"model_num:{model_num[0]}", MessageLevel.Info);
  2065. }
  2066. string colorItem = item.FirstOrDefault(f => f.Contains("color="));
  2067. if (colorItem != null)
  2068. {
  2069. color[0] = colorItem.Replace("color=", "").Trim();
  2070. SendTaskMessage($"color:{color[0]}", MessageLevel.Info);
  2071. }
  2072. string ppidItem = item.FirstOrDefault(f => f.Contains("ppid="));
  2073. if (ppidItem != null)
  2074. {
  2075. ppid[0] = ppidItem.Replace("ppid=", "").Trim();
  2076. SendTaskMessage($"ppid:{ppid[0]}", MessageLevel.Info);
  2077. }
  2078. string stageItem = item.FirstOrDefault(f => f.Contains("stage="));
  2079. if (stageItem != null)
  2080. {
  2081. stage[0] = stageItem.Replace("stage=", "").Trim();
  2082. SendTaskMessage($"stage:{stage[0]}", MessageLevel.Info);
  2083. }
  2084. string kbsnitem = item.FirstOrDefault(f => f.Contains("KB="));
  2085. if (kbsnitem != null)
  2086. {
  2087. kb_sn[0] = kbsnitem.Replace("KB=", "").Trim();
  2088. SendTaskMessage($"KB:{kb_sn[0]}", MessageLevel.Info);
  2089. }
  2090. string kbpnsnitem = item.FirstOrDefault(f => f.Contains("KB_PN="));
  2091. if (kbpnsnitem != null)
  2092. {
  2093. kb_pn[0] = kbpnsnitem.Replace("KB_PN=", "").Trim();
  2094. SendTaskMessage($"KB_PN:{kb_pn[0]}", MessageLevel.Info);
  2095. }
  2096. FinalResultStatus = "检测中";
  2097. FinalResultText = "检测中";
  2098. var item1 = await _systemDatabaseService.QueryProductWithMesALLAsync();
  2099. foreach (var q in item1)
  2100. {
  2101. if (!string.IsNullOrEmpty(q.ProductName))
  2102. {
  2103. ProductWithMes productWithMes = new ProductWithMes();
  2104. ProductList = new ObservableCollection<ProductModel>(_productService.GetAllProducts());
  2105. Guid productId = Guid.Empty;
  2106. foreach (var itt in ProductList)
  2107. {
  2108. if (itt.Name == q.ProductName)
  2109. {
  2110. productId = itt.ID;
  2111. break;
  2112. }
  2113. }
  2114. if (_configService.GetSystemConfiguration().IsTP_AOI)
  2115. {
  2116. if (currentProduct.ID != productId && q.ProductLoad.Contains(kb_pn[0]))
  2117. {
  2118. //切换产品
  2119. SendTaskMessage($"开始切换产品{q.ProductName}", MessageLevel.Error);
  2120. var _ = Application.Current.Dispatcher.BeginInvoke(new Action(() => { _dialogService.ShowDialog("UProgressBar", rst => { }); }));
  2121. await Task.Delay(50);
  2122. _ = App.Current.Dispatcher.BeginInvoke(new Action(() =>
  2123. {
  2124. _eventAggregator.GetEvent<ProgressNotification>().Publish(new UProgressBar.ProgressParameter { Maximum = 2, Minimum = 0, SubTitle = $"切换产品...", Message = $"切换{q.ProductName}产品中...", Value = 0 });
  2125. }));
  2126. await _productService.LoadProductAsync(productId);
  2127. _productService.SetCurrentProduct(productId);
  2128. await WritePositionToPlcAsync();
  2129. _ = App.Current.Dispatcher.BeginInvoke(new Action(() =>
  2130. {
  2131. _eventAggregator.GetEvent<ProgressNotification>().Publish(new UProgressBar.ProgressParameter { Maximum = 2, Minimum = 0, SubTitle = $"切换产品...", Message = $"{Lang.完成}", Value = -1 });
  2132. }));
  2133. SendTaskMessage($"切换产品成功", MessageLevel.Debug);
  2134. break;
  2135. }
  2136. }
  2137. else
  2138. {
  2139. if (currentProduct.ID != productId && model_num[0].Contains(q.ProductCode))
  2140. {
  2141. //切换产品
  2142. SendTaskMessage($"开始切换产品{q.ProductCode}", MessageLevel.Error);
  2143. var _ = Application.Current.Dispatcher.BeginInvoke(new Action(() => { _dialogService.ShowDialog("UProgressBar", rst => { }); }));
  2144. await Task.Delay(50);
  2145. _ = App.Current.Dispatcher.BeginInvoke(new Action(() =>
  2146. {
  2147. _eventAggregator.GetEvent<ProgressNotification>().Publish(new UProgressBar.ProgressParameter { Maximum = 2, Minimum = 0, SubTitle = $"切换产品...", Message = $"切换{q.ProductName}产品中...", Value = 0 });
  2148. }));
  2149. await _productService.LoadProductAsync(productId);
  2150. _productService.SetCurrentProduct(productId);
  2151. await WritePositionToPlcAsync();
  2152. _ = App.Current.Dispatcher.BeginInvoke(new Action(() =>
  2153. {
  2154. _eventAggregator.GetEvent<ProgressNotification>().Publish(new UProgressBar.ProgressParameter { Maximum = 2, Minimum = 0, SubTitle = $"切换产品...", Message = $"{Lang.完成}", Value = -1 });
  2155. }));
  2156. SendTaskMessage($"切换产品成功", MessageLevel.Debug);
  2157. break;
  2158. }
  2159. }
  2160. }
  2161. }
  2162. }
  2163. LogHelper.WriteLogMes($"第二次询问mes成功");
  2164. SendTaskMessage($"第二次询问mes成功:{response2}", MessageLevel.Debug);
  2165. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)1);
  2166. }
  2167. else
  2168. {
  2169. LogHelper.WriteLogMes($"第二次询问mes失败");
  2170. SendTaskMessage($"第二次询问mes失败:{response2}", MessageLevel.Error);
  2171. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)3);
  2172. string[] item = response2.Split('\n');
  2173. string snItem = item.FirstOrDefault(f => f.Contains("sn="));
  2174. if (snItem != null)
  2175. {
  2176. ProductMainSN = snItem.Replace("sn=", "").Trim();
  2177. _productService.CurrentProductCode = ProductMainSN;
  2178. await plc.WriteNodeAsync<string>(string.Format(addressConfig.In_Code.Address, 0), ProductMainSN);
  2179. SendTaskMessage($"产品主sn:{ProductMainSN}", MessageLevel.Info);
  2180. }
  2181. }
  2182. }
  2183. else
  2184. {
  2185. //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
  2186. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)3);
  2187. string[] items = response.Split('\n');
  2188. string snItem = items.FirstOrDefault(f => f.Contains("sn="));
  2189. if (snItem != null)
  2190. {
  2191. ProductMainSN = snItem.Replace("sn=", "").Trim();
  2192. _productService.CurrentProductCode = ProductMainSN;
  2193. await plc.WriteNodeAsync<string>(string.Format(addressConfig.In_Code.Address, 0), ProductMainSN);
  2194. SendTaskMessage($"产品主sn:{ProductMainSN}", MessageLevel.Info);
  2195. }
  2196. LogHelper.WriteLogMes($"询问mes失败");
  2197. SendTaskMessage($"询问mes失败:{response}", MessageLevel.Error);
  2198. }
  2199. }
  2200. else
  2201. {
  2202. SendTaskMessage($"扫码失败", MessageLevel.Alarm);
  2203. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)3);
  2204. }
  2205. return;
  2206. }
  2207. if (sysConfig.CodeUse2 == true && cameraIndex == 1)
  2208. {
  2209. var cts = new CancellationTokenSource();
  2210. // CameraProcedureId 存储的是具体的视觉流程 Id(ProcedureModel.Id),
  2211. // 需要在所有 CameraProcedures 的 ProcedureModels 中查找匹配的流程。
  2212. ProcedureModel selectedProcedure = null;
  2213. try
  2214. {
  2215. cameraProcedures = currentProduct.CameraProcedures;
  2216. if (cameraProcedures != null)
  2217. {
  2218. foreach (var cp in cameraProcedures)
  2219. {
  2220. if (cp?.ProcedureModels == null) continue;
  2221. selectedProcedure = cp.ProcedureModels.FirstOrDefault(pm => pm.Id == targetPoint.CameraProcedureId1);
  2222. if (selectedProcedure != null) break;
  2223. }
  2224. }
  2225. }
  2226. catch (Exception ex)
  2227. {
  2228. LogHelper.WriteLogError("查找 AOI 点位对应视觉流程时出错", ex);
  2229. }
  2230. if (selectedProcedure == null)
  2231. {
  2232. SendTaskMessage($"未找到 AOI 点位对应的视觉流程,Point#{cameraIndex} ProcedureId={targetPoint.CameraProcedureId1}", MessageLevel.Alarm);
  2233. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)2);
  2234. return;
  2235. }
  2236. var ctsAll = new CancellationTokenSource();
  2237. if (selectedProcedure.Id == currentProduct.FixedDownCameraProcedureId && sysConfig.TurnOnAllLightUse == true)
  2238. {
  2239. await _remoteCommandService.SetLightBeforePhoto(selectedProcedure);
  2240. }
  2241. var visionResult = await _remoteCommandService.ExecutePhotoGetSinglePoint2(selectedProcedure, null, null, ctsAll.Token);
  2242. if (visionResult.IsSucceed)
  2243. {
  2244. code = visionResult.X;
  2245. ProductMainSN = visionResult.X;
  2246. SendTaskMessage($"扫码成功,SN:{code}", MessageLevel.Info);
  2247. //这里缺少从MES获取产品配方的内容,需要补充
  2248. _LastMesCheckTime[0] = (await _mesService.GetServerTimeAsync(code, 2)).Now;
  2249. //_LastMesCheckTime[1] = DateTime.Now;
  2250. LogHelper.WriteLogMes($"【mes开始QUERY】");
  2251. SendTaskMessage($"mes开始QUERY", MessageLevel.Info);
  2252. (bool isSuccess, string response) = await _mesService.StationGetAsync(code, "", 2);//询问mes
  2253. if (isSuccess)
  2254. {
  2255. //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
  2256. LogHelper.WriteLogMes($"询问mes成功");
  2257. SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
  2258. if (response != "MES功能未启用!")
  2259. {
  2260. string[] items = response.Split('\n');
  2261. string snItem = items.FirstOrDefault(f => f.Contains("sn="));
  2262. if (snItem != null)
  2263. {
  2264. ProductMainSN = snItem.Replace("sn=", "").Trim();
  2265. _productService.CurrentProductCode = ProductMainSN;
  2266. await plc.WriteNodeAsync<string>(string.Format(addressConfig.In_Code.Address, 0), ProductMainSN);
  2267. SendTaskMessage($"产品主sn:{ProductMainSN}", MessageLevel.Info);
  2268. }
  2269. string woItem = items.FirstOrDefault(f => f.Contains("wo="));
  2270. if (woItem != null)
  2271. {
  2272. wo[0] = woItem.Replace("wo=", "").Trim();
  2273. SendTaskMessage($"产品wo:{wo[0]}", MessageLevel.Info);
  2274. }
  2275. string modelItem = items.FirstOrDefault(f => f.Contains("model_num="));
  2276. if (modelItem != null)
  2277. {
  2278. model_num[0] = modelItem.Replace("model_num=", "").Trim();
  2279. SendTaskMessage($"model_num:{model_num[0]}", MessageLevel.Info);
  2280. }
  2281. string colorItem = items.FirstOrDefault(f => f.Contains("color="));
  2282. if (colorItem != null)
  2283. {
  2284. color[0] = colorItem.Replace("color=", "").Trim();
  2285. SendTaskMessage($"color:{color[0]}", MessageLevel.Info);
  2286. }
  2287. string ppidItem = items.FirstOrDefault(f => f.Contains("ppid="));
  2288. if (ppidItem != null)
  2289. {
  2290. ppid[0] = ppidItem.Replace("ppid=", "").Trim();
  2291. SendTaskMessage($"ppid:{ppid[0]}", MessageLevel.Info);
  2292. }
  2293. string stageItem = items.FirstOrDefault(f => f.Contains("stage="));
  2294. if (stageItem != null)
  2295. {
  2296. stage[0] = stageItem.Replace("stage=", "").Trim();
  2297. SendTaskMessage($"stage:{stage[0]}", MessageLevel.Info);
  2298. }
  2299. string kbsnitem = items.FirstOrDefault(f => f.Contains("KB="));
  2300. if (kbsnitem != null)
  2301. {
  2302. kb_sn[0] = kbsnitem.Replace("KB=", "").Trim();
  2303. SendTaskMessage($"KB:{kb_sn[0]}", MessageLevel.Info);
  2304. }
  2305. string kbpnsnitem = items.FirstOrDefault(f => f.Contains("KB_PN="));
  2306. if (kbpnsnitem != null)
  2307. {
  2308. kb_pn[0] = kbpnsnitem.Replace("KB_PN=", "").Trim();
  2309. SendTaskMessage($"KB_PN:{kb_pn[0]}", MessageLevel.Info);
  2310. }
  2311. FinalResultStatus = "检测中";
  2312. FinalResultText = "检测中";
  2313. var item1 = await _systemDatabaseService.QueryProductWithMesALLAsync();
  2314. foreach (var q in item1)
  2315. {
  2316. if (!string.IsNullOrEmpty(q.ProductName))
  2317. {
  2318. ProductWithMes productWithMes = new ProductWithMes();
  2319. ProductList = new ObservableCollection<ProductModel>(_productService.GetAllProducts());
  2320. Guid productId = Guid.Empty;
  2321. foreach (var itt in ProductList)
  2322. {
  2323. if (itt.Name == q.ProductName)
  2324. {
  2325. productId = itt.ID;
  2326. break;
  2327. }
  2328. }
  2329. if (_configService.GetSystemConfiguration().IsTP_AOI)
  2330. {
  2331. if (currentProduct.ID != productId && q.ProductLoad.Contains(kb_pn[0]))
  2332. {
  2333. //切换产品
  2334. SendTaskMessage($"开始切换产品{q.ProductName}", MessageLevel.Error);
  2335. var _ = Application.Current.Dispatcher.BeginInvoke(new Action(() => { _dialogService.ShowDialog("UProgressBar", rst => { }); }));
  2336. await Task.Delay(50);
  2337. _ = App.Current.Dispatcher.BeginInvoke(new Action(() =>
  2338. {
  2339. _eventAggregator.GetEvent<ProgressNotification>().Publish(new UProgressBar.ProgressParameter { Maximum = 2, Minimum = 0, SubTitle = $"切换产品...", Message = $"切换{q.ProductName}产品中...", Value = 0 });
  2340. }));
  2341. await _productService.LoadProductAsync(productId);
  2342. _productService.SetCurrentProduct(productId);
  2343. await WritePositionToPlcAsync();
  2344. _ = App.Current.Dispatcher.BeginInvoke(new Action(() =>
  2345. {
  2346. _eventAggregator.GetEvent<ProgressNotification>().Publish(new UProgressBar.ProgressParameter { Maximum = 2, Minimum = 0, SubTitle = $"切换产品...", Message = $"{Lang.完成}", Value = -1 });
  2347. }));
  2348. SendTaskMessage($"切换产品成功", MessageLevel.Debug);
  2349. break;
  2350. }
  2351. }
  2352. else
  2353. {
  2354. if (currentProduct.ID != productId && model_num[0].Contains(q.ProductCode))
  2355. {
  2356. //切换产品
  2357. SendTaskMessage($"开始切换产品{q.ProductCode}", MessageLevel.Error);
  2358. var _ = Application.Current.Dispatcher.BeginInvoke(new Action(() => { _dialogService.ShowDialog("UProgressBar", rst => { }); }));
  2359. await Task.Delay(50);
  2360. _ = App.Current.Dispatcher.BeginInvoke(new Action(() =>
  2361. {
  2362. _eventAggregator.GetEvent<ProgressNotification>().Publish(new UProgressBar.ProgressParameter { Maximum = 2, Minimum = 0, SubTitle = $"切换产品...", Message = $"切换{q.ProductName}产品中...", Value = 0 });
  2363. }));
  2364. await _productService.LoadProductAsync(productId);
  2365. _productService.SetCurrentProduct(productId);
  2366. await WritePositionToPlcAsync();
  2367. _ = App.Current.Dispatcher.BeginInvoke(new Action(() =>
  2368. {
  2369. _eventAggregator.GetEvent<ProgressNotification>().Publish(new UProgressBar.ProgressParameter { Maximum = 2, Minimum = 0, SubTitle = $"切换产品...", Message = $"{Lang.完成}", Value = -1 });
  2370. }));
  2371. SendTaskMessage($"切换产品成功", MessageLevel.Debug);
  2372. break;
  2373. }
  2374. }
  2375. }
  2376. }
  2377. }
  2378. LogHelper.WriteLogMes($"【mes结束QUERY】");
  2379. SendTaskMessage($"mes结束QUERY", MessageLevel.Info);
  2380. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)1);
  2381. return;
  2382. }
  2383. else
  2384. {
  2385. //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
  2386. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)3);
  2387. string[] items = response.Split('\n');
  2388. string snItem = items.FirstOrDefault(f => f.Contains("sn="));
  2389. if (snItem != null)
  2390. {
  2391. ProductMainSN = snItem.Replace("sn=", "").Trim();
  2392. _productService.CurrentProductCode = ProductMainSN;
  2393. await plc.WriteNodeAsync<string>(string.Format(addressConfig.In_Code.Address, 0), ProductMainSN);
  2394. SendTaskMessage($"产品主sn:{ProductMainSN}", MessageLevel.Info);
  2395. }
  2396. LogHelper.WriteLogMes($"询问mes失败");
  2397. SendTaskMessage($"询问mes失败:{response}", MessageLevel.Error);
  2398. }
  2399. }
  2400. else
  2401. {
  2402. SendTaskMessage($"扫码失败", MessageLevel.Alarm);
  2403. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)3);
  2404. }
  2405. return;
  2406. }
  2407. #endregion
  2408. //不能使用全局变量,不然并发的时候会被清除掉,所以局部变量
  2409. var _ImageTaskList = new List<Task<(bool IsSucceed, ICogImage[] Images, string Message, int cameraIndex, Guid procedureId)>>();
  2410. foreach (var prcId in procIds)
  2411. {
  2412. ProcedureModel selectedProcedure = null;
  2413. try
  2414. {
  2415. foreach (var cp in cameraProcedures)
  2416. {
  2417. if (cp?.ProcedureModels == null) continue;
  2418. selectedProcedure = cp.ProcedureModels.FirstOrDefault(pm => pm.Id == prcId);
  2419. if (selectedProcedure != null) break;
  2420. }
  2421. }
  2422. catch (Exception ex)
  2423. {
  2424. LogHelper.WriteLogError("查找 AOI 点位对应视觉流程时出错", ex);
  2425. }
  2426. // [DEBUG] 光源控制已临时屏蔽
  2427. // if (sysConfig.TurnOnAllLightUse == false)
  2428. // {
  2429. // await _remoteCommandService.SetLightBeforePhoto(selectedProcedure);
  2430. // }
  2431. if (sysConfig.PhotosUse == true)
  2432. {
  2433. bool Is3dPhoto = Is3D(prcId);
  2434. var tt = await GrabImageEx(cameraIndex, prcId, Is3dPhoto, currentProduct, sysConfig);
  2435. if (tt.IsSucceed == false)
  2436. {
  2437. SendTaskMessage($"图像采集失败!{cameraIndex}: {prcId}", MessageLevel.Alarm);
  2438. return;
  2439. }
  2440. await ExecuteProcedureAsync(cameraIndex, prcId, tt.imges, Is3dPhoto, currentProduct);
  2441. if (targetPoint.AiVision == 1)
  2442. {
  2443. var targetPoint2 = currentProduct.AoiPoints?.FirstOrDefault(p => p.Number == targetPoint.AiVision);
  2444. await ExecuteProcedureAsync(targetPoint.AiVision, targetPoint2.CameraProcedureId1, tt.imges, Is3dPhoto, currentProduct);
  2445. }
  2446. }
  2447. else
  2448. {
  2449. bool Is3dPhoto = Is3D(prcId);
  2450. _ImageTaskList.Add(GrabImageEx(cameraIndex, prcId, Is3dPhoto, currentProduct, sysConfig));
  2451. if (targetPoint.AiVision == 1)
  2452. {
  2453. break;
  2454. }
  2455. }
  2456. // [DEBUG] 光源控制已临时屏蔽
  2457. // if (sysConfig.TurnOnAllLightUse == false)
  2458. // {
  2459. // await _remoteCommandService.TurnOffLightAfterPhoto(selectedProcedure);
  2460. // }
  2461. }
  2462. if (cameraIndex != currentProduct.PhotoCountStop)
  2463. {
  2464. //直接放行,执行下一个检测点
  2465. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)1);
  2466. }
  2467. if (_ImageTaskList.Count > 0)//如果2D取图有队列
  2468. {
  2469. //并发
  2470. _ = Task.Run(async () =>
  2471. {
  2472. var ImageTaskResults = await Task.WhenAll(_ImageTaskList);
  2473. // 并发执行所有 ToolBlock(每个 ToolBlock 在独立 STA 线程中运行)
  2474. var procedureTasks = new List<Task>();
  2475. foreach (var item in ImageTaskResults)
  2476. {
  2477. if (item.IsSucceed)
  2478. {
  2479. bool Is3d = Is3D(item.procedureId);
  2480. if (targetPoint.AiVision == 1)
  2481. {
  2482. var targetPoint2 = currentProduct.AoiPoints?.FirstOrDefault(p => p.Number == cameraIndex);
  2483. procedureTasks.Add(ExecuteProcedureAsync(targetPoint.AiVision, targetPoint2.CameraProcedureId2, item.Images, Is3d, currentProduct));
  2484. }
  2485. procedureTasks.Add(ExecuteProcedureAsync(item.cameraIndex, item.procedureId, item.Images, Is3d, currentProduct));
  2486. }
  2487. else
  2488. {
  2489. SendTaskMessage($"图像采集失败!{item.cameraIndex}: {item.procedureId}", MessageLevel.Alarm);
  2490. AllResult.Add(false);
  2491. ClearCountdown();
  2492. }
  2493. }
  2494. // 等待所有并发 ToolBlock 执行完成
  2495. await Task.WhenAll(procedureTasks);
  2496. });
  2497. }
  2498. //如果最后一个拍照点,则需要等待前面所有的拍照处理完成
  2499. if (cameraIndex == currentProduct.PhotoCountStop)
  2500. {
  2501. //结果输出
  2502. bool resultFlog = true;
  2503. //等待所有的图像处理流程处理完成
  2504. //之前版本使用的是lock机制无法进行并发操作,目前能完美进行并发且能等待所有任务完成
  2505. // 异步等待 countdown,避免同步阻塞线程池线程
  2506. bool countdownCompleted;
  2507. using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)))
  2508. {
  2509. try
  2510. {
  2511. await Task.Run(() => countdown.Wait(cts.Token), cts.Token);
  2512. countdownCompleted = true;
  2513. }
  2514. catch (OperationCanceledException)
  2515. {
  2516. countdownCompleted = false;
  2517. }
  2518. }
  2519. if (!countdownCompleted)
  2520. {
  2521. SendTaskMessage($"检测流程超时!预期{countdown.InitialCount}个模板完成,实际仅完成{countdown.InitialCount - countdown.CurrentCount}个,按NG处理", MessageLevel.Alarm);
  2522. LogHelper.WriteLogInfo($"Countdown超时:预期{countdown.InitialCount}个信号,当前剩余{countdown.CurrentCount}个");
  2523. ClearCountdown();
  2524. resultFlog = false;
  2525. // 跳过后续结果判断,直接按NG写入PLC
  2526. SendTaskMessage($"检测执行失败(超时)", MessageLevel.Alarm);
  2527. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)2);
  2528. FinalResultStatus = "NG";
  2529. FinalResultText = "NG(超时)";
  2530. return;
  2531. }
  2532. if (sysConfig.PhotosUse == true)
  2533. {
  2534. foreach (var item in lockResultsAll)
  2535. {
  2536. if (item.PhotoPassed == "NG")
  2537. {
  2538. resultFlog = false;
  2539. break;
  2540. }
  2541. }
  2542. }
  2543. else
  2544. {
  2545. foreach (var item in AllResult)
  2546. {
  2547. if (!item)
  2548. {
  2549. resultFlog = false;
  2550. break;
  2551. }
  2552. }
  2553. }
  2554. //全部OK
  2555. if (resultFlog)
  2556. {
  2557. SendTaskMessage($"检测执行成功", MessageLevel.Debug);
  2558. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)1);
  2559. FinalResultStatus = "OK";
  2560. FinalResultText = "OK";
  2561. return;
  2562. }
  2563. //存在NG
  2564. else
  2565. {
  2566. SendTaskMessage($"检测执行失败", MessageLevel.Alarm);
  2567. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)2);
  2568. FinalResultStatus = "NG";
  2569. FinalResultText = "NG";
  2570. return;
  2571. }
  2572. }
  2573. return;
  2574. }
  2575. else
  2576. {
  2577. SendTaskMessage($"触发固定相机检测拍照信号已关闭", MessageLevel.Alarm);
  2578. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)0);
  2579. }
  2580. }
  2581. }
  2582. // 翻转相机检测拍照
  2583. else if (addressConfig.In_FzCameraPixExe.Address.Contains(tuple.nodeId))
  2584. {
  2585. if (tuple.value is bool state)
  2586. {
  2587. if (_LastFzCameracheckExe != state)
  2588. {
  2589. _LastFzCameracheckExe = state;
  2590. }
  2591. else
  2592. {
  2593. return;
  2594. }
  2595. if (state)
  2596. {
  2597. SendTaskMessage("触发翻转相机拍照", MessageLevel.Debug);
  2598. var code = plc.ReadNode<string>(string.Format(addressConfig.In_Code.Address, 1));
  2599. //这里缺少从MES获取产品配方的内容,需要补充
  2600. _LastMesCheckTime[5] = (await _mesService.GetServerTimeAsync(code, 2)).Now;
  2601. var stationConfig2 = _configService.GetDeviceInfo(0);
  2602. LogHelper.WriteLogMes($"【mes开始QUERY】");
  2603. SendTaskMessage($"mes开始QUERY", MessageLevel.Info);
  2604. (bool isSuccess, string response) = await _mesService.StationGetExAsync(code, "", 2);
  2605. if (isSuccess)
  2606. {
  2607. string ProductMainSN_Temp = "";
  2608. LogHelper.WriteLogMes($"询问mes成功");
  2609. SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
  2610. string[] item = response.Split('\n');
  2611. //获取过度件sn
  2612. string snItem = item.FirstOrDefault(f => f.Contains("sn="));
  2613. if (snItem != null)
  2614. {
  2615. ProductMainSN_Temp = snItem.Replace("sn=", "").Trim();
  2616. SendTaskMessage($"过度件sn:{ProductMainSN_Temp}", MessageLevel.Info);
  2617. }
  2618. LogHelper.WriteLogMes($"询问mes成功");
  2619. SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
  2620. //20260214,螺丝机特别版
  2621. (bool isSuccess2, string response2) = await _mesService.StationGetAsync(ProductMainSN_Temp, "", 2);//询问mes
  2622. if (isSuccess2)
  2623. {
  2624. LogHelper.WriteLogMes($"询问mes成功");
  2625. SendTaskMessage($"询问mes成功:{response2}", MessageLevel.Debug);
  2626. string[] items = response2.Split('\n');
  2627. //获取产品主sn和wo用于后续上传数据使用
  2628. string snItem2 = items.FirstOrDefault(f => f.Contains("sn="));
  2629. if (snItem2 != null)
  2630. {
  2631. var codesn = snItem2.Replace("sn=", "").Trim();
  2632. SendTaskMessage($"产品主sn:{codesn}", MessageLevel.Info);
  2633. }
  2634. LogHelper.WriteLogMes($"第二次询问mes成功");
  2635. SendTaskMessage($"第二次询问mes成功:{response2}", MessageLevel.Debug);
  2636. }
  2637. else
  2638. {
  2639. LogHelper.WriteLogMes($"第二次询问mes失败");
  2640. SendTaskMessage($"第二次询问mes失败:{response2}", MessageLevel.Error);
  2641. await plc.WriteNodeAsync(addressConfig.Out_FzCameraPickStatus.Address, (Int16)2);
  2642. return;
  2643. }
  2644. }
  2645. else
  2646. {
  2647. LogHelper.WriteLogMes($"询问mes失败");
  2648. SendTaskMessage($"询问mes失败:{response}", MessageLevel.Error);
  2649. await plc.WriteNodeAsync(addressConfig.Out_FzCameraPickStatus.Address, (Int16)2);
  2650. return;
  2651. }
  2652. Guid FzCameraProcedureId = currentProduct.FzCameraProcedureId;
  2653. var FzCameraProcess = _productService.GetCurrentProductProcedureModelById(FzCameraProcedureId);
  2654. if (FzCameraProcess == null)
  2655. {
  2656. SendTaskMessage($"未找到翻转相机视觉流程,流程ID: {FzCameraProcedureId}", MessageLevel.Alarm);
  2657. await plc.WriteNodeAsync(addressConfig.Out_FzCameraPickStatus.Address, (Int16)2);
  2658. return;
  2659. }
  2660. SendTaskMessage($"开始执行翻转相机视觉流程", MessageLevel.Debug);
  2661. var _cts = new CancellationTokenSource();
  2662. await _remoteCommandService.SetLightBeforePhoto(FzCameraProcess);
  2663. var (FzCameraResult, outputCollection) = await _remoteCommandService.ExecutePhotoAsync(FzCameraProcess);
  2664. if (FzCameraResult)
  2665. {
  2666. SendTaskMessage("翻转相机拍照成功", MessageLevel.Debug);
  2667. await plc.WriteNodeAsync(addressConfig.Out_FzCameraPickStatus.Address, (Int16)1);
  2668. }
  2669. else
  2670. {
  2671. SendTaskMessage("翻转相机拍照失败", MessageLevel.Alarm);
  2672. await plc.WriteNodeAsync(addressConfig.Out_FzCameraPickStatus.Address, (Int16)2);
  2673. }
  2674. }
  2675. else
  2676. {
  2677. SendTaskMessage($"触发翻转相机检测拍照信号已关闭", MessageLevel.Alarm);
  2678. await plc.WriteNodeAsync(addressConfig.Out_FzCameraPickStatus.Address, (Int16)0);
  2679. }
  2680. }
  2681. }
  2682. //切换成自动运行模式
  2683. else if (addressConfig.AutoRunning.Address.Contains(tuple.nodeId))
  2684. {
  2685. if (tuple.value is bool state)
  2686. {
  2687. if (_LastAutoRunning != state)
  2688. {
  2689. _LastAutoRunning = state;
  2690. }
  2691. else
  2692. {
  2693. return;
  2694. }
  2695. if (state)
  2696. {
  2697. CurrentRunStatus();
  2698. SendTaskMessage("收到切换成自动模式", MessageLevel.Info);
  2699. }
  2700. }
  2701. }
  2702. //切换成维修模式
  2703. else if (addressConfig.ManualMode.Address.Contains(tuple.nodeId))
  2704. {
  2705. if (tuple.value is bool state)
  2706. {
  2707. if (_LastManualMode != state)
  2708. {
  2709. _LastManualMode = state;
  2710. }
  2711. else
  2712. {
  2713. return;
  2714. }
  2715. if (state)
  2716. {
  2717. CurrentDisplayMode = RunDisplayMode.Manual;
  2718. SendTaskMessage("收到切换成维修模式", MessageLevel.Info);
  2719. }
  2720. }
  2721. }
  2722. //切换成流线模式
  2723. else if (addressConfig.ClearMode.Address.Contains(tuple.nodeId))
  2724. {
  2725. if (tuple.value is bool state)
  2726. {
  2727. if (_LastClearMode != state)
  2728. {
  2729. _LastClearMode = state;
  2730. }
  2731. else
  2732. {
  2733. return;
  2734. }
  2735. if (state)
  2736. {
  2737. CurrentDisplayMode = RunDisplayMode.Clear;
  2738. SendTaskMessage("收到切换成流线模式", MessageLevel.Info);
  2739. }
  2740. }
  2741. }
  2742. //读取PLC生产CT
  2743. else if (addressConfig.WorkCt.Address.Contains(tuple.nodeId))
  2744. {
  2745. if (tuple.value is bool state)
  2746. {
  2747. if (_Lastworkct != state)
  2748. {
  2749. _Lastworkct = state;
  2750. }
  2751. else
  2752. {
  2753. return;
  2754. }
  2755. if (state)
  2756. {
  2757. Int32 cttime = plc.ReadNode<Int32>(addressConfig.In_CycleTimeBefor.Address);
  2758. SendTaskMessage($"读取PLC记录CT:{cttime}", MessageLevel.Info);
  2759. CTtime2 = Convert.ToDouble(cttime);
  2760. }
  2761. }
  2762. }
  2763. // 过站检查
  2764. else
  2765. {
  2766. for (int i = 0; i < 10; i++)
  2767. {
  2768. if (string.Format(addressConfig.In_MesCheck.Address, i).Contains(tuple.nodeId))
  2769. {
  2770. if (tuple.value is Int16 state)
  2771. {
  2772. if (_LastMesCheck[i] != state)
  2773. {
  2774. _LastMesCheck[i] = state;
  2775. }
  2776. else
  2777. {
  2778. return;
  2779. }
  2780. if (i == 1)
  2781. {
  2782. SendTaskMessage($"收到人工站请求不处理", MessageLevel.Debug);
  2783. return;
  2784. }
  2785. var sysConfig = _configService.GetSystemConfiguration();
  2786. if (sysConfig.CodeUse == true && state == 1)
  2787. {
  2788. await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)1);
  2789. return;
  2790. }
  2791. if (sysConfig.CodeUse2 == true && state == 1)
  2792. {
  2793. await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)1);
  2794. return;
  2795. }
  2796. if (sysConfig.CodeUse == false && sysConfig.CodeUse2 == false)
  2797. {
  2798. code = plc.ReadNode<string>(string.Format(addressConfig.In_Code.Address, i));
  2799. }
  2800. //var homeview = _container.Resolve<HomeViewModel>();
  2801. if (i == 0)
  2802. {
  2803. SendTaskMessage($"收到当前过站检查请求(当站是否生产)...", MessageLevel.Debug);
  2804. }
  2805. else
  2806. {
  2807. SendTaskMessage($"收到{i}过站检查请求(当站是否生产)...", MessageLevel.Debug);
  2808. }
  2809. //过站检查
  2810. if (state == 1)
  2811. {
  2812. //这里缺少从MES获取产品配方的内容,需要补充
  2813. _LastMesCheckTime[i] = (await _mesService.GetServerTimeAsync(code, 2)).Now;
  2814. DeviceInfo stationConfig2 = new DeviceInfo();
  2815. try
  2816. {
  2817. stationConfig2 = _configService.GetDeviceInfo(i);
  2818. }
  2819. catch (Exception)
  2820. {
  2821. await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)2);
  2822. SendTaskMessage($"设置无当前站点:{i}", MessageLevel.Error);
  2823. return;
  2824. }
  2825. //if (homeview.IsNoCode == false)
  2826. //{
  2827. // var device = _configService.GetDeviceInfo(0);
  2828. // code = device.XnSN;
  2829. //}
  2830. LogHelper.WriteLogMes($"【mes开始QUERY】");
  2831. SendTaskMessage($"mes开始QUERY", MessageLevel.Info);
  2832. ShowMes_Query = false;
  2833. (bool isSuccess, string response) = await _mesService.StationGetExAsync(code, "", 2);
  2834. if (isSuccess)
  2835. {
  2836. string ProductMainSN_Temp = "";
  2837. LogHelper.WriteLogMes($"询问mes成功");
  2838. SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
  2839. string[] item2 = response.Split('\n');
  2840. //获取过度件sn
  2841. string snItem2 = item2.FirstOrDefault(f => f.Contains("sn="));
  2842. if (snItem2 != null)
  2843. {
  2844. ProductMainSN_Temp = snItem2.Replace("sn=", "").Trim();
  2845. SendTaskMessage($"过度件sn:{ProductMainSN_Temp}", MessageLevel.Info);
  2846. }
  2847. LogHelper.WriteLogMes($"询问mes成功");
  2848. SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
  2849. (bool isSuccess2, string response2) = await _mesService.StationGetAsync(ProductMainSN_Temp, "", 2);//询问mes
  2850. if (isSuccess)
  2851. {
  2852. string[] item = response2.Split('\n');
  2853. //获取产品主sn和wo用于后续上传数据使用
  2854. string snItem = item.FirstOrDefault(f => f.Contains("sn="));
  2855. if (snItem != null)
  2856. {
  2857. if (i == 0)
  2858. {
  2859. ProductMainSN = snItem.Replace("sn=", "").Trim();
  2860. _productService.CurrentProductCode = ProductMainSN;
  2861. }
  2862. SendTaskMessage($"产品主sn:{ProductMainSN}", MessageLevel.Info);
  2863. }
  2864. string woItem = item.FirstOrDefault(f => f.Contains("wo="));
  2865. if (woItem != null)
  2866. {
  2867. wo[i] = woItem.Replace("wo=", "").Trim();
  2868. SendTaskMessage($"工单信息:{wo[i]}", MessageLevel.Info);
  2869. }
  2870. string modelItem = item.FirstOrDefault(f => f.Contains("model_num="));
  2871. if (modelItem != null)
  2872. {
  2873. model_num[i] = modelItem.Replace("model_num=", "").Trim();
  2874. SendTaskMessage($"model_num:{model_num[i]}", MessageLevel.Info);
  2875. }
  2876. string colorItem = item.FirstOrDefault(f => f.Contains("color="));
  2877. if (colorItem != null)
  2878. {
  2879. color[i] = colorItem.Replace("color=", "").Trim();
  2880. SendTaskMessage($"color:{color[i]}", MessageLevel.Info);
  2881. }
  2882. string ppidItem = item.FirstOrDefault(f => f.Contains("ppid="));
  2883. if (ppidItem != null)
  2884. {
  2885. ppid[i] = ppidItem.Replace("ppid=", "").Trim();
  2886. SendTaskMessage($"ppid:{ppid[i]}", MessageLevel.Info);
  2887. }
  2888. string stageItem = item.FirstOrDefault(f => f.Contains("stage="));
  2889. if (stageItem != null)
  2890. {
  2891. stage[i] = stageItem.Replace("stage=", "").Trim();
  2892. SendTaskMessage($"stage:{stage[i]}", MessageLevel.Info);
  2893. }
  2894. string kbsnitem = item.FirstOrDefault(f => f.Contains("KB="));
  2895. if (kbsnitem != null)
  2896. {
  2897. kb_sn[i] = kbsnitem.Replace("KB=", "").Trim();
  2898. SendTaskMessage($"KB:{kb_sn[i]}", MessageLevel.Info);
  2899. }
  2900. string kbpnsnitem = item.FirstOrDefault(f => f.Contains("KB_PN="));
  2901. if (kbpnsnitem != null)
  2902. {
  2903. kb_pn[i] = kbpnsnitem.Replace("KB_PN=", "").Trim();
  2904. SendTaskMessage($"KB_PN:{kb_pn[i]}", MessageLevel.Info);
  2905. }
  2906. ShowMes_Query = true;
  2907. FinalResultStatus = "检测中";
  2908. FinalResultText = "检测中";
  2909. if (stationConfig2.EnableMES)
  2910. {
  2911. //切换产品
  2912. if (i == 0)//i=0时才会切换产品
  2913. {
  2914. try
  2915. {
  2916. //var q = await _systemDatabaseService.QueryProductFromMesAsync(model_num, color);
  2917. var item1 = await _systemDatabaseService.QueryProductWithMesALLAsync();
  2918. foreach (var q in item1)
  2919. {
  2920. if (!string.IsNullOrEmpty(q.ProductName))
  2921. {
  2922. ProductWithMes productWithMes = new ProductWithMes();
  2923. ProductList = new ObservableCollection<ProductModel>(_productService.GetAllProducts());
  2924. Guid productId = Guid.Empty;
  2925. foreach (var itt in ProductList)
  2926. {
  2927. if (itt.Name == q.ProductName)
  2928. {
  2929. productId = itt.ID;
  2930. break;
  2931. }
  2932. }
  2933. if (_configService.GetSystemConfiguration().IsTP_AOI)
  2934. {
  2935. if (currentProduct.ID != productId && q.ProductLoad.Contains(kb_pn[i]))
  2936. {
  2937. //切换产品
  2938. SendTaskMessage($"开始切换产品{q.ProductName}", MessageLevel.Error);
  2939. var _ = Application.Current.Dispatcher.BeginInvoke(new Action(() => { _dialogService.ShowDialog("UProgressBar", rst => { }); }));
  2940. await Task.Delay(50);
  2941. _ = App.Current.Dispatcher.BeginInvoke(new Action(() =>
  2942. {
  2943. _eventAggregator.GetEvent<ProgressNotification>().Publish(new UProgressBar.ProgressParameter { Maximum = 2, Minimum = 0, SubTitle = $"切换产品...", Message = $"切换{q.ProductName}产品中...", Value = 0 });
  2944. }));
  2945. await _productService.LoadProductAsync(productId);
  2946. _productService.SetCurrentProduct(productId);
  2947. await WritePositionToPlcAsync();
  2948. _ = App.Current.Dispatcher.BeginInvoke(new Action(() =>
  2949. {
  2950. _eventAggregator.GetEvent<ProgressNotification>().Publish(new UProgressBar.ProgressParameter { Maximum = 2, Minimum = 0, SubTitle = $"切换产品...", Message = $"{Lang.完成}", Value = -1 });
  2951. }));
  2952. SendTaskMessage($"切换产品成功", MessageLevel.Debug);
  2953. break;
  2954. }
  2955. }
  2956. else
  2957. {
  2958. if (currentProduct.ID != productId && model_num[i].Contains(q.ProductCode))
  2959. {
  2960. //切换产品
  2961. SendTaskMessage($"开始切换产品{q.ProductCode}", MessageLevel.Error);
  2962. var _ = Application.Current.Dispatcher.BeginInvoke(new Action(() => { _dialogService.ShowDialog("UProgressBar", rst => { }); }));
  2963. await Task.Delay(50);
  2964. _ = App.Current.Dispatcher.BeginInvoke(new Action(() =>
  2965. {
  2966. _eventAggregator.GetEvent<ProgressNotification>().Publish(new UProgressBar.ProgressParameter { Maximum = 2, Minimum = 0, SubTitle = $"切换产品...", Message = $"切换{q.ProductName}产品中...", Value = 0 });
  2967. }));
  2968. await _productService.LoadProductAsync(productId);
  2969. _productService.SetCurrentProduct(productId);
  2970. await WritePositionToPlcAsync();
  2971. _ = App.Current.Dispatcher.BeginInvoke(new Action(() =>
  2972. {
  2973. _eventAggregator.GetEvent<ProgressNotification>().Publish(new UProgressBar.ProgressParameter { Maximum = 2, Minimum = 0, SubTitle = $"切换产品...", Message = $"{Lang.完成}", Value = -1 });
  2974. }));
  2975. SendTaskMessage($"切换产品成功", MessageLevel.Debug);
  2976. break;
  2977. }
  2978. }
  2979. }
  2980. }
  2981. }
  2982. catch (Exception ex)
  2983. { SendTaskMessage($"切换产品异常" + ex.Message, MessageLevel.Error); }
  2984. }
  2985. }
  2986. await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)1);
  2987. LogHelper.WriteLogMes($"【mes结束QUERY】");
  2988. SendTaskMessage($"mes结束QUERY", MessageLevel.Info);
  2989. // return;
  2990. }
  2991. else
  2992. {
  2993. await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)2);
  2994. LogHelper.WriteLogMes($"二次询问mes失败");
  2995. SendTaskMessage($"二次询问mes失败:{response}", MessageLevel.Error);
  2996. string[] item = response2.Split('\n');
  2997. //获取产品主sn和wo用于后续上传数据使用
  2998. string snItem = item.FirstOrDefault(f => f.Contains("sn="));
  2999. if (snItem != null)
  3000. {
  3001. if (i == 0)
  3002. {
  3003. ProductMainSN = snItem.Replace("sn=", "").Trim();
  3004. _productService.CurrentProductCode = ProductMainSN;
  3005. }
  3006. SendTaskMessage($"产品主sn:{ProductMainSN}", MessageLevel.Info);
  3007. }
  3008. }
  3009. }
  3010. else
  3011. {
  3012. await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)2);
  3013. LogHelper.WriteLogMes($"询问mes失败");
  3014. SendTaskMessage($"询问mes失败:{response}", MessageLevel.Error);
  3015. }
  3016. }
  3017. // 上传本站数据
  3018. else if (state == 2)
  3019. {
  3020. //获取当前工位的配置
  3021. var stationConfig = _configService.GetDeviceInfo(0);
  3022. List<DataFormCtq> DFC = new List<DataFormCtq>();
  3023. List<DataFormCtq> NGDFC = new List<DataFormCtq>();
  3024. SendTaskMessage($"收到{i}上传本站数据请求...", MessageLevel.Debug);
  3025. //读取产品结果
  3026. Int16 resultIndex = plc.ReadNode<Int16>(string.Format(addressConfig.In_Result.Address, i));
  3027. SendTaskMessage($"读取plc结果{resultIndex}", MessageLevel.Debug);
  3028. if (!sysConfig.IsInOut)
  3029. {
  3030. await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)3);
  3031. }
  3032. //这里缺少上传MES的本站数据结果及开始和结束时间,需要补充
  3033. //从服务器中获取当前时间
  3034. var serverTimeResult = await _mesService.GetServerTimeAsync(ProductMainSN, 2);
  3035. double ct = serverTimeResult.Now.Subtract(_LastMesCheckTime[i]).TotalSeconds;
  3036. if (i == 0)
  3037. {
  3038. CTtime = ct;
  3039. }
  3040. if (stationConfig.EnableMES)
  3041. {
  3042. //目前只记录当前站
  3043. if (i == 0)
  3044. await _systemDatabaseService.RecordProductionAsync(new ProductionRecord()
  3045. {
  3046. ProductName = currentProduct.Name,
  3047. ProductCode = ProductMainSN,
  3048. DeviceId = i,
  3049. DeviceName = "",
  3050. Category = resultIndex == 1 ? "OK" : "NG",
  3051. Quantity = 1,
  3052. Remark = $"TotalSeconds:{DateTime.UtcNow.Subtract(_LastMesCheckTime[i]).TotalSeconds.ToString("F2")}",
  3053. });
  3054. }
  3055. LogHelper.WriteLogMes($"【mes开始ADD】");
  3056. SendTaskMessage($"mes开始ADD", MessageLevel.Info);
  3057. string Error = "";
  3058. StringBuilder submitDataError = new StringBuilder();
  3059. foreach (var item in lockResultsAll)
  3060. {
  3061. if (item.PhotoPassed == "NG")
  3062. {
  3063. submitDataError.Append(item.PhotoName + "_" + item.ResultData + "_Fail,");
  3064. Error += item.PhotoName + "_" + item.ResultData + "_Fail;";
  3065. }
  3066. }
  3067. StringBuilder submitData = new StringBuilder();
  3068. StringBuilder submitData2 = new StringBuilder();
  3069. StringBuilder submitData3 = new StringBuilder();
  3070. StringBuilder submitData4 = new StringBuilder();
  3071. foreach (var item in lockResultsAll)
  3072. {
  3073. //if (submitData.Length < 3500)
  3074. //{
  3075. // submitData.Append($"{item.PhotoName}={item.ResultData}");
  3076. //}
  3077. string PhotoName = item.PhotoName.Replace("?", "%3F").Replace("#", "%23").Replace("+", "%2B").Replace("/", "%2F").Replace("%", "%25");
  3078. string data = $"{PhotoName}={item.ResultData}&";
  3079. //string data = $"{item.PhotoName}={item.ResultData}&";
  3080. // 按顺序填满,不超过 3500 就加进去
  3081. if (submitData.Length + data.Length <= 3500)
  3082. {
  3083. submitData.Append(data);
  3084. }
  3085. else if (submitData2.Length + data.Length <= 3500)
  3086. {
  3087. submitData2.Append(data);
  3088. }
  3089. else if (submitData3.Length + data.Length <= 3500)
  3090. {
  3091. submitData3.Append(data);
  3092. }
  3093. else if (submitData4.Length + data.Length <= 3500)
  3094. {
  3095. submitData4.Append(data);
  3096. }
  3097. else
  3098. {
  3099. SendTaskMessage($"上传数据数据超出4组最大限制", MessageLevel.Error);
  3100. }
  3101. }
  3102. bool allSuccess = true;
  3103. bool ok = false;
  3104. string name = currentProduct.Name;
  3105. if (stationConfig.SaveCsvkeyData)
  3106. {
  3107. if (keyData != null)
  3108. {
  3109. ok = CheckKeyBoardValue(keyData, name, out string msg);
  3110. }
  3111. if (ok && resultIndex == 1 ? true : false && isValueOk)
  3112. {
  3113. ShowMes_Result = true;
  3114. }
  3115. else
  3116. {
  3117. ShowMes_Result = false;
  3118. }
  3119. }
  3120. ShowMes_Result = resultIndex == 1 ? true : false;
  3121. //StringBuilder submitDataError2 = new StringBuilder();
  3122. //foreach (var item in keyData)
  3123. //{
  3124. // submitData.Append($"{item.Key}={item.Value}");
  3125. //}
  3126. //keyData.Clear();
  3127. // ShowMes_Result = resultIndex == 1 ? true : false;
  3128. //(bool isSuccess, string response) = await _mesService.SubmitGetAsync(ProductMainSN, "", submitData.ToString(), resultIndex == 1 ? true : false, _LastMesCheckTime[i], serverTimeResult.Now);
  3129. if (submitData.Length > 0)
  3130. {
  3131. string data1 = submitData.ToString().TrimEnd('&');
  3132. (bool isSuccess, string response) = await _mesService.SubmitGetAsync(0, ProductMainSN, "", submitData.ToString(), ShowMes_Result, submitDataError.ToString(), _LastMesCheckTime[i], serverTimeResult.Now);
  3133. allSuccess &= isSuccess;
  3134. }
  3135. if (submitData2.Length > 0)
  3136. {
  3137. string data2 = submitData2.ToString().TrimEnd('&');
  3138. (bool isSuccess, string response) = await _mesService.SubmitGetAsync(1, ProductMainSN, "", submitData2.ToString(), ShowMes_Result, submitDataError.ToString(), _LastMesCheckTime[i], serverTimeResult.Now);
  3139. allSuccess &= isSuccess;
  3140. }
  3141. if (submitData3.Length > 0)
  3142. {
  3143. string data3 = submitData3.ToString().TrimEnd('&');
  3144. (bool isSuccess, string response) = await _mesService.SubmitGetAsync(2, ProductMainSN, "", submitData3.ToString(), ShowMes_Result, submitDataError.ToString(), _LastMesCheckTime[i], serverTimeResult.Now);
  3145. allSuccess &= isSuccess;
  3146. }
  3147. if (submitData4.Length > 0)
  3148. {
  3149. string data4 = submitData4.ToString().TrimEnd('&');
  3150. (bool isSuccess, string response) = await _mesService.SubmitGetAsync(3, ProductMainSN, "", submitData4.ToString(), ShowMes_Result, submitDataError.ToString(), _LastMesCheckTime[i], serverTimeResult.Now);
  3151. allSuccess &= isSuccess;
  3152. }
  3153. if (allSuccess)
  3154. {
  3155. LogHelper.WriteLogMes($"上传mes成功");
  3156. SendTaskMessage($"上传mes成功", MessageLevel.Debug);
  3157. }
  3158. else
  3159. {
  3160. LogHelper.WriteLogMes($"上传mes失败");
  3161. SendTaskMessage($"上传mes失败", MessageLevel.Error);
  3162. }
  3163. if (sysConfig.IsInOut)
  3164. {
  3165. await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)3);
  3166. }
  3167. //是否保存当前的产品记录至CSV?
  3168. if (stationConfig.SaveCsv)
  3169. {
  3170. string saveppid = "NA";
  3171. string names = currentProduct.Name;
  3172. if (stationConfig.SaveCsvPPID) saveppid = ppid[i];
  3173. // Dictionary<string, double> adjacentDiffDict1 = GetAdjacentDiffDict(keyData1);
  3174. //判断锁付路径字符串是否为空,如果不为空则保存,否则不保存
  3175. if (!string.IsNullOrEmpty(stationConfig.SaveCsvPath))
  3176. {
  3177. foreach (var item in lockResultsAll)
  3178. {
  3179. for (int k = 1; k <= 8; k++)
  3180. {
  3181. if (item.PhotoName == "-" + "_" + k.ToString())
  3182. {
  3183. item.PhotoName = "'-" + "_" + k.ToString();
  3184. }
  3185. if (item.PhotoName == "=" + "_" + k.ToString())
  3186. {
  3187. item.PhotoName = "'=" + "_" + k.ToString();
  3188. }
  3189. //if (item.PhotoName=="-"+k.ToString())
  3190. //{
  3191. // item.PhotoName = "_" + k.ToString();
  3192. //}
  3193. }
  3194. string temp_COMMODITY_TYPE = stationConfig.DataInfo.COMMODITY_TYPE;
  3195. if (item.PhotoName.Contains("A1b"))
  3196. {
  3197. temp_COMMODITY_TYPE = "Mechanical Hardware LCD CVR";
  3198. }
  3199. if (item.PhotoName.Contains("A1c") || item.PhotoName.Contains("A1d"))
  3200. {
  3201. temp_COMMODITY_TYPE = "Mechanical Hardware_LCD BZL";
  3202. }
  3203. if (item.PhotoName.Contains("A2"))
  3204. {
  3205. temp_COMMODITY_TYPE = "CAMERA";
  3206. }
  3207. if (item.PhotoName.Contains("A4"))
  3208. {
  3209. temp_COMMODITY_TYPE = "Mechanical Hardware_HNG CVR";
  3210. }
  3211. if (item.PhotoName.Contains("C4"))
  3212. {
  3213. temp_COMMODITY_TYPE = "Mechanical Hardware_PLMRST";
  3214. }
  3215. if (item.PhotoName.Contains("D5"))
  3216. {
  3217. temp_COMMODITY_TYPE = "Mechanical Hardware_DOOR";
  3218. }
  3219. if (item.PhotoName.Contains("B1"))
  3220. {
  3221. temp_COMMODITY_TYPE = "Mechanical Hardware_KB BKT";
  3222. }
  3223. if (item.PhotoName.Contains("B2"))
  3224. {
  3225. temp_COMMODITY_TYPE = "Mechanical Hardware_TP BKT";
  3226. }
  3227. if (item.PhotoName.Contains("D1"))
  3228. {
  3229. temp_COMMODITY_TYPE = "Mechanical Hardware_BTM CVR";
  3230. }
  3231. DFC.Add(new DataFormCtq
  3232. {
  3233. PPID = saveppid,
  3234. PROCESS_NAME = stationConfig.DataInfo.PROCESS_NAME,
  3235. PROCESS_START_TIME = _LastMesCheckTime[i].ToString("yyyy-MM-ddTHH:mm:ss.fffffff") + "+08:00",
  3236. CTQ_NAME = item.PhotoName,
  3237. CTQ_VALUE = item.ResultData.Replace(",", ";"),
  3238. //CTQ_VALUEE=item.ResultData1,
  3239. CTQ_LSL = item.DownLimit,
  3240. CTQ_USL = item.UpLimit,
  3241. PROCESS_END_TIME = serverTimeResult.Now.ToString("yyyy-MM-ddTHH:mm:ss.fffffff") + "+08:00",
  3242. SUPPLIER_NAME = stationConfig.DataInfo.SUPPLIER_NAME,
  3243. COMMODITY_TYPE = temp_COMMODITY_TYPE,
  3244. REVISION = stationConfig.DataInfo.REVISION + "_" + stage[i],//
  3245. WO = wo[i],//
  3246. MFG_LOT = stationConfig.DataInfo.MFG_LOT,//
  3247. MFG_ASSY_LINE = stationConfig.DataInfo.MFG_ASSY_LINE,
  3248. PROCESS_OUTCOME = item.PhotoPassed == "OK" ? "PASS" : "FAIL",
  3249. PROCESS_MACHINE_ID = stationConfig.DataInfo.PROCESS_MACHINE_ID,
  3250. CTQ_UNIT_OF_MEASURE = "mm",
  3251. //ERROR_MESSAGE = item.PhotoPassed == "OK" ? "" : $"{item.PhotoName} OOS",
  3252. ERROR_MESSAGE = item.PhotoPassed == "OK" ? "" : $"{item.PhotoName}_{item.ResultData.Replace(",", ";")}",
  3253. PD_ATTR_01 = ProductMainSN,//
  3254. PD_ATTR_02 = item.MidLimit,
  3255. PD_ATTR_04 = code,
  3256. PD_ATTR_05 = CTtime.ToString(),
  3257. PD_ATTR_06 = CTtime2.ToString(),
  3258. });
  3259. }
  3260. if (stationConfig.SaveCsvkeyData)
  3261. {
  3262. Dictionary<string, double> adjacentDiffDict = GetAdjacentDiffDict(keyData, names);
  3263. foreach (var items in adjacentDiffDict)
  3264. {
  3265. string pairkey = items.Key;
  3266. string diffvalue = items.Value.ToString("F3");
  3267. DFC.Add(new DataFormCtq
  3268. {
  3269. PPID = saveppid,
  3270. PROCESS_NAME = stationConfig.DataInfo.PROCESS_NAME,
  3271. PROCESS_START_TIME = _LastMesCheckTime[i].ToString("yyyy-MM-ddTHH:mm:ss.fffffff") + "+08:00",
  3272. CTQ_NAME = pairkey,
  3273. CTQ_VALUE = diffvalue,
  3274. CTQ_LSL = "-0.3",
  3275. CTQ_USL = "0.3",
  3276. PROCESS_END_TIME = serverTimeResult.Now.ToString("yyyy-MM-ddTHH:mm:ss.fffffff") + "+08:00",
  3277. SUPPLIER_NAME = stationConfig.DataInfo.SUPPLIER_NAME,
  3278. COMMODITY_TYPE = stationConfig.DataInfo.COMMODITY_TYPE,
  3279. REVISION = stationConfig.DataInfo.REVISION + "_" + stage[i],//
  3280. WO = wo[i],//
  3281. MFG_LOT = stationConfig.DataInfo.MFG_LOT,//
  3282. MFG_ASSY_LINE = stationConfig.DataInfo.MFG_ASSY_LINE,
  3283. PROCESS_OUTCOME = ok ? "Pass" : "FAIL",
  3284. PROCESS_MACHINE_ID = stationConfig.DataInfo.PROCESS_MACHINE_ID,
  3285. CTQ_UNIT_OF_MEASURE = "mm",
  3286. ERROR_MESSAGE = ok ? "" : $"{diffvalue}",
  3287. PD_ATTR_01 = ProductMainSN,//
  3288. PD_ATTR_02 = "",
  3289. PD_ATTR_03 = "",
  3290. PD_ATTR_04 = code,
  3291. PD_ATTR_05 = CTtime.ToString(),
  3292. PD_ATTR_06 = CTtime2.ToString(),
  3293. });
  3294. }
  3295. foreach (var items in keyData1)
  3296. {
  3297. string pairkey1 = items.Key;
  3298. string diffvalue1 = items.Value.ToString("F3");
  3299. DFC.Add(new DataFormCtq
  3300. {
  3301. PPID = saveppid,
  3302. PROCESS_NAME = stationConfig.DataInfo.PROCESS_NAME,
  3303. PROCESS_START_TIME = _LastMesCheckTime[i].ToString("yyyy-MM-ddTHH:mm:ss.fffffff") + "+08:00",
  3304. CTQ_NAME = pairkey1,
  3305. CTQ_VALUE = diffvalue1,
  3306. CTQ_LSL = "0",
  3307. CTQ_USL = "0.3",
  3308. PROCESS_END_TIME = serverTimeResult.Now.ToString("yyyy-MM-ddTHH:mm:ss.fffffff") + "+08:00",
  3309. SUPPLIER_NAME = stationConfig.DataInfo.SUPPLIER_NAME,
  3310. COMMODITY_TYPE = stationConfig.DataInfo.COMMODITY_TYPE,
  3311. REVISION = stationConfig.DataInfo.REVISION + "_" + stage[i],//
  3312. WO = wo[i],//
  3313. MFG_LOT = stationConfig.DataInfo.MFG_LOT,//
  3314. MFG_ASSY_LINE = stationConfig.DataInfo.MFG_ASSY_LINE,
  3315. PROCESS_OUTCOME = ok ? "Pass" : "FAIL",
  3316. PROCESS_MACHINE_ID = stationConfig.DataInfo.PROCESS_MACHINE_ID,
  3317. CTQ_UNIT_OF_MEASURE = "mm",
  3318. ERROR_MESSAGE = ok ? "" : $"{diffvalue1}",
  3319. PD_ATTR_01 = ProductMainSN,//
  3320. PD_ATTR_02 = "0.15",
  3321. PD_ATTR_03 = "",
  3322. PD_ATTR_04 = code,
  3323. PD_ATTR_05 = CTtime.ToString(),
  3324. PD_ATTR_06 = CTtime2.ToString(),
  3325. });
  3326. }
  3327. }
  3328. //测试使用,强制上传mes为pass
  3329. //if (sysConfig.IsMesResult)
  3330. //{
  3331. // resultToMes.Clear();
  3332. //}
  3333. bool recordResult = RecordStationResult(i, DFC, ProductMainSN, serverTimeResult.Now.Subtract(_LastMesCheckTime[i]).TotalSeconds, _LastMesCheckTime[i], stationConfig.SaveCsvPath, out string actualCsvPath);
  3334. // bool recordResult1 = WriteProductLog( ProductMainSN, serverTimeResult.Now.Subtract(_LastMesCheckTime[i]).TotalSeconds, _LastMesCheckTime[i], stationConfig.SaveCsvPath, DFC);
  3335. //keyData.Clear();
  3336. if (recordResult)
  3337. {
  3338. SendTaskMessage($"{i}:{stationConfig.DeviceName}产品记录保存成功", MessageLevel.Debug);
  3339. if (Error != "")
  3340. {
  3341. NGDFC.Add(new DataFormCtq
  3342. {
  3343. PROCESS_START_TIME = _LastMesCheckTime[i].ToString("yyyy-MM-ddTHH:mm:ss.fffffff") + "+08:00",
  3344. PROCESS_END_TIME = serverTimeResult.Now.ToString("yyyy-MM-ddTHH:mm:ss.fffffff") + "+08:00",
  3345. ERROR_MESSAGE = Error,
  3346. PD_ATTR_01 = ProductMainSN,//
  3347. });
  3348. RecordStationNGResult(NGDFC, _LastMesCheckTime[i]);
  3349. }
  3350. //上传数据
  3351. try
  3352. {
  3353. if (stationConfig.EnableMES)
  3354. {
  3355. DateTime dt = DateTime.Now;
  3356. string filename = $"{ProductMainSN}_{dt.ToString("yyyyMMddHHmmss")}";
  3357. var device = _configService.GetDeviceInfo(i);
  3358. var config = _configService.GetSystemConfiguration();
  3359. string filePath = "";
  3360. (bool isSuc, string resp) = await _mesService.SendFtpFileAsync(ProductMainSN, filename);
  3361. if (isSuc)
  3362. {
  3363. LogHelper.WriteLogMes($"上传数据成功");
  3364. SendTaskMessage($"上传数据成功", MessageLevel.Debug);
  3365. //filePath = $"D:\\Image\\Recored\\{dt.ToString("yyyy-MM")}\\{dt.ToString("MM-dd")}\\{currentProduct.Name}\\{ProductMainSN}";
  3366. filePath = $"{PhotoPath}\\Recored\\{dt.ToString("yyyy-MM")}\\{dt.ToString("MM-dd")}\\{currentProduct.Name}\\{ProductMainSN}";
  3367. string csvfilename = $"{i}_{stationConfig.DeviceName}_{dt.ToString("yyyy-MM-dd")}";
  3368. //复制csv — 使用 actualCsvPath(可能是备份路径)
  3369. string target_csv = Path.Combine(filePath, Path.GetFileName(actualCsvPath));
  3370. try
  3371. {
  3372. if (!Directory.Exists(filePath))
  3373. Directory.CreateDirectory(filePath);
  3374. File.Copy(actualCsvPath, target_csv, true);
  3375. }
  3376. catch (Exception copyEx)
  3377. {
  3378. LogHelper.WriteLogError($"复制CSV到上传目录失败: src={actualCsvPath}, dst={target_csv}", copyEx);
  3379. }
  3380. //复制log
  3381. try
  3382. {
  3383. string source_log = $"..\\Log\\LogInfo\\{dt.ToString("yyyy-MM")}\\{dt.ToString("yyyy-MM-dd")}.txt";
  3384. string target_log = Path.Combine(filePath, Path.GetFileName(source_log));
  3385. File.Copy(source_log, target_log, true);
  3386. }
  3387. catch (Exception copyLogEx)
  3388. {
  3389. LogHelper.WriteLogError($"复制Log到上传目录失败", copyLogEx);
  3390. }
  3391. try { CompressionImage(filePath, filename, device.Station, device.FixtureId); }
  3392. catch (Exception zipEx) { LogHelper.WriteLogError($"压缩图片文件夹失败", zipEx); }
  3393. //上传csv
  3394. bool isAfter20 = dt.Hour >= 20;
  3395. //判断是否是新的一天
  3396. bool isNewDay = dt.Date != _lastCompressDate.Date;
  3397. //当天还没执行过压缩
  3398. if (isAfter20 && isNewDay && !_hasCompressedToday)
  3399. {
  3400. // 执行压缩 — 使用 actualCsvPath
  3401. try
  3402. {
  3403. CompressionSingleCsv(actualCsvPath, csvfilename, device.Station, device.FixtureId);
  3404. _lastCompressDate = dt;
  3405. _hasCompressedToday = true;
  3406. LogHelper.WriteLogMes("csv上传数据成功");
  3407. SendTaskMessage($"csv上传数据成功", MessageLevel.Debug);
  3408. }
  3409. catch (Exception csvZipEx) { LogHelper.WriteLogError($"压缩CSV文件失败", csvZipEx); }
  3410. }
  3411. // 跨天后重置当天执行标记
  3412. if (!isNewDay && _hasCompressedToday)
  3413. {
  3414. _hasCompressedToday = false;
  3415. }
  3416. }
  3417. else
  3418. {
  3419. LogHelper.WriteLogMes($"上传数据失败");
  3420. SendTaskMessage($"上传数据失败", MessageLevel.Error);
  3421. }
  3422. }
  3423. else
  3424. {
  3425. LogHelper.WriteLogMes($"未启用mes");
  3426. SendTaskMessage($"未启用mes", MessageLevel.Error);
  3427. }
  3428. }
  3429. catch (Exception ex)
  3430. {
  3431. SendTaskMessage($"上传数据时出错:{ex.Message}", MessageLevel.Error);
  3432. LogHelper.WriteLogError($"上传数据时出错", ex);
  3433. }
  3434. }
  3435. else
  3436. {
  3437. SendTaskMessage($"{i}:{stationConfig.DeviceName}产品记录保存失败", MessageLevel.Error);
  3438. }
  3439. }
  3440. else
  3441. {
  3442. SendTaskMessage($"{i}:{stationConfig.DeviceName}工位未配置保存路径,无法保存产品记录", MessageLevel.Error);
  3443. }
  3444. }
  3445. else
  3446. {
  3447. SendTaskMessage($"{i}:{stationConfig.DeviceName}工位未配置保存产品记录", MessageLevel.Debug);
  3448. }
  3449. if (stationConfig.SaveCsvJmp)
  3450. {
  3451. bool kb = WriteProductLogKB(DFC, ProductMainSN);
  3452. bool tp = WriteProductLogTP(DFC, ProductMainSN);
  3453. if (kb)
  3454. {
  3455. SendTaskMessage($"保存KB键盘格JMP数据成功", MessageLevel.Debug);
  3456. }
  3457. else
  3458. {
  3459. SendTaskMessage($"保存KB键盘格JMP数据失败", MessageLevel.Error);
  3460. }
  3461. if (tp)
  3462. {
  3463. SendTaskMessage($"保存TP键盘格JMP数据成功", MessageLevel.Debug);
  3464. }
  3465. else
  3466. {
  3467. SendTaskMessage($"保存TP键盘格JMP数据失败", MessageLevel.Error);
  3468. }
  3469. }
  3470. else
  3471. {
  3472. SendTaskMessage($"未启用保存键盘格JMP数据", MessageLevel.Info);
  3473. }
  3474. LogHelper.WriteLogMes($"【mes结束ADD】");
  3475. SendTaskMessage($"mes结束ADD", MessageLevel.Info);
  3476. }
  3477. else
  3478. {
  3479. SendTaskMessage($"{i}过站检查信号:state={state},处理为默认状态", MessageLevel.Alarm);
  3480. await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)0);
  3481. }
  3482. }
  3483. }
  3484. }
  3485. }
  3486. }
  3487. catch (Exception ex)
  3488. {
  3489. SendTaskMessage(ex.Message, MessageLevel.Error);
  3490. }
  3491. }
  3492. /// <summary>
  3493. /// 异步执行流程拍照
  3494. /// </summary>
  3495. /// <param name="pointIndex"></param>
  3496. /// <param name="procedureId"></param>
  3497. /// <returns></returns>
  3498. private Task<(bool IsSucceed, bool[] Result, string Message)> ExecuteProcedureAsync(int pointIndex, Guid procedureId)
  3499. {
  3500. return Task.Run(async () =>
  3501. {
  3502. List<bool> results = new List<bool>();
  3503. // 获取当前产品
  3504. var currentProduct = _productService.GetCurrentProduct();
  3505. if (currentProduct == null)
  3506. {
  3507. return (false, null, "当前产品为空,未加载产品!");
  3508. }
  3509. var cameraProcedures = currentProduct.CameraProcedures;
  3510. if (cameraProcedures == null || cameraProcedures.Count == 0)
  3511. {
  3512. SendTaskMessage($"当前产品未配置 CameraProcedures,无法执行视觉流程", MessageLevel.Alarm);
  3513. return (false, null, $"当前产品未配置 CameraProcedures,无法执行视觉流程");
  3514. }
  3515. var ctsAll = new CancellationTokenSource();
  3516. try
  3517. {
  3518. ProcedureModel selectedProcedure = null;
  3519. try
  3520. {
  3521. foreach (var cp in cameraProcedures)
  3522. {
  3523. if (cp?.ProcedureModels == null) continue;
  3524. selectedProcedure = cp.ProcedureModels.FirstOrDefault(pm => pm.Id == procedureId);
  3525. if (selectedProcedure != null) break;
  3526. }
  3527. }
  3528. catch (Exception ex)
  3529. {
  3530. LogHelper.WriteLogError("查找 AOI 点位对应视觉流程时出错", ex);
  3531. }
  3532. if (selectedProcedure == null)
  3533. {
  3534. SendTaskMessage($"未找到 AOI 点位对应的视觉流程,Point#{pointIndex} ProcedureId={pointIndex}", MessageLevel.Alarm);
  3535. return (false, null, $"未找到 AOI 点位对应的视觉流程,Point#{pointIndex} ProcedureId={procedureId}");
  3536. }
  3537. SendTaskMessage($"开始执行 AOI 流程 (Point#{pointIndex}) 流程Id={pointIndex}", MessageLevel.Debug);
  3538. try
  3539. {
  3540. //1. 执行拍照,图像处理
  3541. var visionResult = await _remoteCommandService.ExecutePhotoGetSinglePoint1(selectedProcedure, null, null, ctsAll.Token);
  3542. if (visionResult.Count == 0)
  3543. {
  3544. SendTaskMessage("Count值为0", MessageLevel.Alarm);
  3545. return (false, null, $"未找到 AOI 点位对应的视觉流程,Point#{pointIndex} ProcedureId={procedureId}");
  3546. }
  3547. //2. 结果分析
  3548. for (int i = 1; i <= visionResult.Count; i++)
  3549. {
  3550. LockResult lockResult1 = new LockResult();
  3551. //if (pointIndex == currentProduct.PhotoCount && selectedProcedure.Id == currentProduct.FixedUpCamera1ProcedureId && i == 1)
  3552. //{
  3553. // lockResult1.Number = 1;
  3554. //}
  3555. string[] strpoints1 = visionResult.Items[i].Split(',');
  3556. lockResult1.PhotoName = strpoints1[0];
  3557. string[] body1 = strpoints1[1].Split(";");
  3558. string body2 = null;
  3559. if (body1.Length == 8)
  3560. {
  3561. body2 = $"{body1[0]},{body1[2]},{body1[4]},{body1[6]}";
  3562. }
  3563. else
  3564. {
  3565. body2 = strpoints1[1];
  3566. }
  3567. lockResult1.ResultData = body2;
  3568. lockResult1.PhotoCode = ProductMainSN;
  3569. var globalParam = currentProduct.GlobalParamListCollection.FirstOrDefault(p => p.Name == strpoints1[0]);
  3570. if (globalParam != null)
  3571. {
  3572. lockResult1.UpLimit = globalParam.Param1;
  3573. lockResult1.DownLimit = globalParam.Param2;
  3574. lockResult1.MidLimit = globalParam.Param5;
  3575. string ResData = strpoints1[1];
  3576. if (ResData.Contains("NA"))
  3577. {
  3578. ResData = "-1000";
  3579. }
  3580. string[] body = ResData.Split(";");
  3581. bool resultflog = true;
  3582. foreach (var item in body)
  3583. {
  3584. if (Convert.ToDouble(item) >= Convert.ToDouble(globalParam.Param2) && Convert.ToDouble(item) <= Convert.ToDouble(globalParam.Param1))
  3585. {
  3586. }
  3587. else
  3588. {
  3589. resultflog = false;
  3590. }
  3591. }
  3592. if (resultflog)
  3593. {
  3594. lockResult1.PhotoPassed = "OK";
  3595. results.Add(true);
  3596. }
  3597. else
  3598. {
  3599. lockResult1.PhotoPassed = "NG";
  3600. results.Add(false);
  3601. }
  3602. }
  3603. lock (_stateLock)
  3604. {
  3605. lockResultsAll.Add(lockResult1);
  3606. }
  3607. // 使用 BeginInvoke(Background) 异步通知 UI
  3608. // Background 优先级确保用户输入(Normal)优先处理
  3609. _ = App.Current.Dispatcher.BeginInvoke(new Action(() =>
  3610. {
  3611. _eventAggregator.GetEvent<LockFinishNotification>().Publish(lockResult1);
  3612. }), System.Windows.Threading.DispatcherPriority.Background);
  3613. }
  3614. //排序
  3615. //lock (_stateLock)
  3616. //{
  3617. // var bf1 = lockResultsAll.OrderBy(p => p.Number);
  3618. // lockResultsAll = new List<LockResult>(bf1);
  3619. //}
  3620. }
  3621. catch (Exception ex)
  3622. {
  3623. LogHelper.WriteLogError("执行 AOI 视觉流程时出错", ex);
  3624. SendTaskMessage($"执行 AOI 视觉流程异常: {ex.Message}", MessageLevel.Alarm);
  3625. }
  3626. return (true, results.ToArray(), $"成功");
  3627. }
  3628. catch (Exception ex)
  3629. {
  3630. LogHelper.WriteLogError("处理固定相机检测拍照时出错", ex);
  3631. return (false, null, $"处理固定相机检测拍照时出错");
  3632. }
  3633. });
  3634. }
  3635. /// <summary>
  3636. /// 异步执行流程拍照
  3637. /// </summary>
  3638. /// <param name="pointIndex"></param>
  3639. /// <param name="procedureId"></param>
  3640. /// <returns></returns>
  3641. private async Task ExecuteProcedureAsync(int pointIndex, Guid procedureId, ICogImage[] images, bool is3dmodel, ProductModel currentProduct)
  3642. {
  3643. List<bool> results = new List<bool>();
  3644. var cameraProcedures = currentProduct.CameraProcedures;
  3645. if (cameraProcedures == null || cameraProcedures.Count == 0)
  3646. {
  3647. SendTaskMessage($"当前产品未配置 CameraProcedures,无法执行视觉流程", MessageLevel.Alarm);
  3648. //return (false, null, $"当前产品未配置 CameraProcedures,无法执行视觉流程");
  3649. AllResult.Add(false);
  3650. }
  3651. var ctsAll = new CancellationTokenSource();
  3652. try
  3653. {
  3654. ProcedureModel selectedProcedure = null;
  3655. try
  3656. {
  3657. foreach (var cp in cameraProcedures)
  3658. {
  3659. if (cp?.ProcedureModels == null) continue;
  3660. selectedProcedure = cp.ProcedureModels.FirstOrDefault(pm => pm.Id == procedureId);
  3661. if (selectedProcedure != null) break;
  3662. }
  3663. }
  3664. catch (Exception ex)
  3665. {
  3666. LogHelper.WriteLogError("查找 AOI 点位对应视觉流程时出错", ex);
  3667. }
  3668. if (selectedProcedure == null)
  3669. {
  3670. SendTaskMessage($"未找到 AOI 点位对应的视觉流程,Point#{pointIndex} ProcedureId={pointIndex}", MessageLevel.Alarm);
  3671. //return (false, null, $"未找到 AOI 点位对应的视觉流程,Point#{pointIndex} ProcedureId={procedureId}");
  3672. AllResult.Add(false);
  3673. }
  3674. SendTaskMessage($"开始执行 AOI 流程 (Point#{pointIndex}) 流程Id={pointIndex}", MessageLevel.Debug);
  3675. try
  3676. {
  3677. var sysConfig = _configService.GetSystemConfiguration();
  3678. if (selectedProcedure.Id == currentProduct.MoveDownCameraLockPhotoProcedureId && sysConfig.TurnOffAllLightUse == true)
  3679. {
  3680. await _remoteCommandService.TurnOffLightAfterPhoto(selectedProcedure);
  3681. }
  3682. PhotoPath = selectedProcedure.SavePath;
  3683. //1. 执行拍照,图像处理
  3684. var visionResult = await _remoteCommandService.ExecutePhotoGetSinglePoint1(selectedProcedure, images, null, null, ctsAll.Token, is3dmodel);
  3685. if (visionResult.Count == 0)
  3686. {
  3687. SendTaskMessage($"未找到 AOI 点位对应的视觉流程,Point#{pointIndex} ProcedureId={procedureId} Count值为0", MessageLevel.Alarm);
  3688. //return (false, null, $"未找到 AOI 点位对应的视觉流程,Point#{pointIndex} ProcedureId={procedureId}");
  3689. AllResult.Add(false);
  3690. }
  3691. //2. 结果分析
  3692. var stationConfig = _configService.GetDeviceInfo(0);
  3693. for (int i = 1; i <= visionResult.Count; i++)
  3694. {
  3695. LockResult lockResult1 = new LockResult();
  3696. try
  3697. {
  3698. string[] strpoints1 = visionResult.Items[i].Split(',');
  3699. string[] body1 = strpoints1[1].Split(";");
  3700. if (body1.Length > 1)
  3701. {
  3702. for (int j = 1; j <= body1.Length; j++)
  3703. {
  3704. lockResult1.PhotoName = strpoints1[0] + "_" + j.ToString();
  3705. lockResult1.ResultData = body1[j - 1];
  3706. lockResult1.PhotoCode = ProductMainSN;
  3707. var globalParam = currentProduct.GlobalParamListCollection.FirstOrDefault(p => p.Name == strpoints1[0]);
  3708. if (globalParam != null)
  3709. {
  3710. lockResult1.UpLimit = globalParam.Param1;
  3711. lockResult1.DownLimit = globalParam.Param2;
  3712. lockResult1.MidLimit = globalParam.Param5;
  3713. string ResData = body1[j - 1];
  3714. if (ResData.Contains("NA"))
  3715. {
  3716. ResData = "-999";
  3717. }
  3718. bool resultflog = true;
  3719. if (Convert.ToDouble(ResData) >= Convert.ToDouble(globalParam.Param2) && Convert.ToDouble(ResData) <= Convert.ToDouble(globalParam.Param1))
  3720. {
  3721. }
  3722. else
  3723. {
  3724. SendTaskMessage($"检测项{lockResult1.PhotoName}结果{ResData}超出上下限!", MessageLevel.Error);
  3725. resultflog = false;
  3726. }
  3727. if (resultflog)
  3728. {
  3729. lockResult1.PhotoPassed = "OK";
  3730. AllResult.Add(true);
  3731. }
  3732. else
  3733. {
  3734. lockResult1.PhotoPassed = "NG";
  3735. AllResult.Add(false);
  3736. }
  3737. }
  3738. lockResultsAll.Add(lockResult1.Copy());
  3739. _ = App.Current.Dispatcher.BeginInvoke(new Action(() =>
  3740. {
  3741. _eventAggregator
  3742. .GetEvent<LockFinishNotification>()
  3743. .Publish(lockResult1);
  3744. }));
  3745. }
  3746. }
  3747. else
  3748. {
  3749. lockResult1.PhotoName = strpoints1[0];
  3750. lockResult1.ResultData = strpoints1[1];
  3751. lockResult1.PhotoCode = ProductMainSN;
  3752. var globalParam = currentProduct.GlobalParamListCollection.FirstOrDefault(p => p.Name == strpoints1[0]);
  3753. if (globalParam != null)
  3754. {
  3755. lockResult1.UpLimit = globalParam.Param1;
  3756. lockResult1.DownLimit = globalParam.Param2;
  3757. lockResult1.MidLimit = globalParam.Param5;
  3758. string ResData = strpoints1[1];
  3759. if (ResData.Contains("NA"))
  3760. {
  3761. ResData = "-1000";
  3762. }
  3763. bool resultflog = true;
  3764. if (Convert.ToDouble(ResData) >= Convert.ToDouble(globalParam.Param2) && Convert.ToDouble(ResData) <= Convert.ToDouble(globalParam.Param1))
  3765. {
  3766. }
  3767. else
  3768. {
  3769. SendTaskMessage($"检测项{lockResult1.PhotoName}结果{ResData}超出上下限!", MessageLevel.Error);
  3770. resultflog = false;
  3771. }
  3772. if (resultflog)
  3773. {
  3774. lockResult1.PhotoPassed = "OK";
  3775. AllResult.Add(true);
  3776. }
  3777. else
  3778. {
  3779. lockResult1.PhotoPassed = "NG";
  3780. AllResult.Add(false);
  3781. }
  3782. }
  3783. lockResultsAll.Add(lockResult1.Copy());
  3784. _ = App.Current.Dispatcher.BeginInvoke(new Action(() =>
  3785. {
  3786. _eventAggregator
  3787. .GetEvent<LockFinishNotification>()
  3788. .Publish(lockResult1);
  3789. }));
  3790. }
  3791. if (stationConfig.SaveCsvkeyData)
  3792. {
  3793. if (body1.Length >= 5)
  3794. {
  3795. string keyName = strpoints1[0].Split('-').Last().Trim();
  3796. List<double> list = new List<double>();
  3797. foreach (string v in body1)
  3798. {
  3799. if (double.TryParse(v.Trim(), out double num))
  3800. {
  3801. if (num == 999)
  3802. {
  3803. continue;
  3804. }
  3805. list.Add(num);
  3806. }
  3807. }
  3808. if (list.Count == 0)
  3809. {
  3810. continue;
  3811. }
  3812. double max = list.Max();
  3813. double min = list.Min();
  3814. double chazhi = max - min;
  3815. double average = list.Average();
  3816. if (max - min > 0.3)
  3817. {
  3818. isValueOk = false;
  3819. SendTaskMessage($"键盘格{keyName}最大值{max}与最小值{min}相差大于0.3!", MessageLevel.Error);
  3820. }
  3821. if (keyData != null)
  3822. {
  3823. if (!keyData.ContainsKey(keyName))
  3824. {
  3825. keyData.TryAdd(keyName, average);
  3826. }
  3827. if (!keyData1.ContainsKey(keyName))
  3828. {
  3829. keyData1.TryAdd(keyName, chazhi);
  3830. }
  3831. }
  3832. else
  3833. {
  3834. keyData.TryAdd(keyName, average);
  3835. keyData1.TryAdd(keyName, chazhi);
  3836. }
  3837. }
  3838. }
  3839. }
  3840. catch (Exception ex)
  3841. {
  3842. SendTaskMessage($"拆分视觉结果出错:{ex}", MessageLevel.Error);
  3843. }
  3844. }
  3845. }
  3846. catch (Exception ex)
  3847. {
  3848. LogHelper.WriteLogError("执行 AOI 视觉流程时出错", ex);
  3849. SendTaskMessage($"执行 AOI 视觉流程异常: {ex.Message}", MessageLevel.Alarm);
  3850. }
  3851. //return (true, results.ToArray(), $"成功");
  3852. }
  3853. catch (Exception ex)
  3854. {
  3855. LogHelper.WriteLogError("处理固定相机检测拍照时出错", ex);
  3856. //return (false, null, $"处理固定相机检测拍照时出错");
  3857. }
  3858. finally
  3859. {
  3860. try
  3861. {
  3862. countdown?.Signal(); // -1
  3863. }
  3864. catch (InvalidOperationException ex)
  3865. {
  3866. LogHelper.WriteLogError("AOI流程完成计数Signal失败", ex);
  3867. }
  3868. }
  3869. }
  3870. private void ClearCountdown()
  3871. {
  3872. try
  3873. {
  3874. var currentCountdown = countdown;
  3875. if (currentCountdown == null || currentCountdown.IsSet)
  3876. {
  3877. return;
  3878. }
  3879. currentCountdown.Signal(currentCountdown.CurrentCount);
  3880. }
  3881. catch (InvalidOperationException ex)
  3882. {
  3883. LogHelper.WriteLogError("AOI流程计数清零失败", ex);
  3884. }
  3885. }
  3886. /// <summary>
  3887. /// 是否是3D相机
  3888. /// </summary>
  3889. /// <param name="procedureId"></param>
  3890. /// <returns></returns>
  3891. private bool Is3D(Guid procedureId)
  3892. {
  3893. // 获取当前产品
  3894. var currentProduct = _productService.GetCurrentProduct();
  3895. if (currentProduct == null)
  3896. {
  3897. return false;
  3898. }
  3899. var cameraProcedures = currentProduct.CameraProcedures;
  3900. if (cameraProcedures == null || cameraProcedures.Count == 0)
  3901. {
  3902. return false;
  3903. }
  3904. ProcedureModel selectedProcedure = null;
  3905. try
  3906. {
  3907. foreach (var cp in cameraProcedures)
  3908. {
  3909. if (cp?.ProcedureModels == null) continue;
  3910. selectedProcedure = cp.ProcedureModels.FirstOrDefault(pm => pm.Id == procedureId);
  3911. if (selectedProcedure != null) break;
  3912. }
  3913. }
  3914. catch (Exception ex)
  3915. {
  3916. LogHelper.WriteLogError("查找 AOI 点位对应视觉流程时出错", ex);
  3917. }
  3918. if (selectedProcedure == null)
  3919. {
  3920. return false;
  3921. }
  3922. var camera = _cameraService.GetCamera(selectedProcedure.CameraId);
  3923. if (camera == null)
  3924. {
  3925. return false;
  3926. }
  3927. return camera.Is3D;
  3928. }
  3929. /// <summary>
  3930. /// 2D相机先采集图像
  3931. /// </summary>
  3932. /// <param name="procedureId"></param>
  3933. /// <returns></returns>
  3934. private async Task<(bool IsSucceed, ICogImage[] imges, string Message)> GrabImage(int pointIndex, Guid procedureId)
  3935. {
  3936. // 获取当前产品
  3937. var currentProduct = _productService.GetCurrentProduct();
  3938. if (currentProduct == null)
  3939. {
  3940. return (false, null, "当前产品为空,未加载产品!");
  3941. }
  3942. var cameraProcedures = currentProduct.CameraProcedures;
  3943. if (cameraProcedures == null || cameraProcedures.Count == 0)
  3944. {
  3945. SendTaskMessage($"当前产品未配置 CameraProcedures,无法执行视觉流程", MessageLevel.Alarm);
  3946. return (false, null, $"当前产品未配置 CameraProcedures,无法执行视觉流程");
  3947. }
  3948. try
  3949. {
  3950. ProcedureModel selectedProcedure = null;
  3951. try
  3952. {
  3953. foreach (var cp in cameraProcedures)
  3954. {
  3955. if (cp?.ProcedureModels == null) continue;
  3956. selectedProcedure = cp.ProcedureModels.FirstOrDefault(pm => pm.Id == procedureId);
  3957. if (selectedProcedure != null) break;
  3958. }
  3959. }
  3960. catch (Exception ex)
  3961. {
  3962. LogHelper.WriteLogError("查找 AOI 点位对应视觉流程时出错", ex);
  3963. }
  3964. if (selectedProcedure == null)
  3965. {
  3966. SendTaskMessage($"未找到 AOI 点位对应的视觉流程,Point#{pointIndex} ProcedureId={pointIndex}", MessageLevel.Alarm);
  3967. return (false, null, $"未找到 AOI 点位对应的视觉流程,Point#{pointIndex} ProcedureId={procedureId}");
  3968. }
  3969. SendTaskMessage($"开始执行 AOI 流程 (Point#{pointIndex}) 流程Id={pointIndex}", MessageLevel.Debug);
  3970. try
  3971. {
  3972. var sysConfig = _configService.GetSystemConfiguration();
  3973. if (selectedProcedure.Id == currentProduct.FixedDownCameraProcedureId && sysConfig.TurnOnAllLightUse == true)
  3974. {
  3975. await _remoteCommandService.SetLightBeforePhoto(selectedProcedure);
  3976. }
  3977. //1. 执行拍照
  3978. //return await _remoteCommandService.ExecuteGrabImageAsync(selectedProcedure);
  3979. }
  3980. catch (Exception ex)
  3981. {
  3982. LogHelper.WriteLogError("执行 AOI 视觉图像采集时出错", ex);
  3983. SendTaskMessage($"执行 AOI 视觉图像采集时出错: {ex.Message}", MessageLevel.Alarm);
  3984. }
  3985. return (false, null, $"图像采集失败");
  3986. }
  3987. catch (Exception ex)
  3988. {
  3989. LogHelper.WriteLogError("处理固定相机检测拍照时出错", ex);
  3990. return (false, null, $"处理固定相机检测拍照时出错");
  3991. }
  3992. }
  3993. /// <summary>
  3994. /// 为所有相机设置批处理点数(会调用具体相机实现的 SetBatchPoints)
  3995. /// </summary>
  3996. /// <param name="points"></param>
  3997. public void SetBatchPoints(int CameraNum, int points)
  3998. {
  3999. try
  4000. {
  4001. if (points == 0 || points < 0)
  4002. {
  4003. return;
  4004. }
  4005. var cameras = _cameraService.GetCameraByNumber(CameraNum);
  4006. if (cameras == null) return;
  4007. try
  4008. {
  4009. // 优先针对已知的 SSZNCamera 类型直接调用
  4010. if (cameras is TeamAAS_VP.Core.Cameras.SSZNCamera sszn)
  4011. {
  4012. sszn.CameraRevFinish = false;
  4013. sszn.SetBatchPoints(points);
  4014. }
  4015. }
  4016. catch (Exception ex)
  4017. {
  4018. LogHelper.WriteLogError($"SetBatchPoints to camera {cameras?.Name} failed", ex);
  4019. }
  4020. }
  4021. catch (Exception ex)
  4022. {
  4023. LogHelper.WriteLogError("SetBatchPoints failed", ex);
  4024. }
  4025. }
  4026. /// <summary>
  4027. /// 为所有相机设置产品配方(会调用具体相机实现的 SetBatchPoints)
  4028. /// </summary>
  4029. /// <param name="points"></param>
  4030. public void SetProducts(int CameraNum, int points)
  4031. {
  4032. try
  4033. {
  4034. if (points < 0)
  4035. {
  4036. return;
  4037. }
  4038. var cameras = _cameraService.GetCameraByNumber(CameraNum);
  4039. if (cameras == null) return;
  4040. try
  4041. {
  4042. // 优先针对已知的 SSZNCamera 类型直接调用
  4043. if (cameras is TeamAAS_VP.Core.Cameras.SSZNCamera sszn)
  4044. {
  4045. sszn.CameraRevFinish = false;
  4046. sszn.SetProducts(CameraNum, points);
  4047. }
  4048. }
  4049. catch (Exception ex)
  4050. {
  4051. LogHelper.WriteLogError($"SetBatchPoints to camera {cameras?.Name} failed", ex);
  4052. }
  4053. }
  4054. catch (Exception ex)
  4055. {
  4056. LogHelper.WriteLogError("SetBatchPoints failed", ex);
  4057. }
  4058. }
  4059. public void SetBatchPoints(int[] CameraSpoints)
  4060. {
  4061. try
  4062. {
  4063. for (int i = 0; i < CameraSpoints.Length; i++)
  4064. {
  4065. SetBatchPoints(i + 1, CameraSpoints[i]);
  4066. }
  4067. }
  4068. catch (Exception ex)
  4069. {
  4070. LogHelper.WriteLogError("SetBatchPoints failed", ex);
  4071. }
  4072. }
  4073. public void SetProducts(int[] CameraSpoints)
  4074. {
  4075. try
  4076. {
  4077. for (int i = 0; i < CameraSpoints.Length; i++)
  4078. {
  4079. SetProducts(i + 1, CameraSpoints[i]);
  4080. }
  4081. }
  4082. catch (Exception ex)
  4083. {
  4084. LogHelper.WriteLogError("SetProducts failed", ex);
  4085. }
  4086. }
  4087. #endregion
  4088. #region 方法
  4089. private void SendTaskMessage(string msg, MessageLevel level)
  4090. {
  4091. _messageQueue.Enqueue(new Models.MessageStruct() { Message = msg, level = level });
  4092. }
  4093. /// <summary>
  4094. /// 定时将消息队列批量推送到 UI 线程,200ms 一次
  4095. /// 使用 DispatcherPriority.Background 避免抢占比用户输入更高优先级的操作
  4096. /// </summary>
  4097. private void FlushMessageQueue()
  4098. {
  4099. if (_messageQueue.IsEmpty) return;
  4100. // 先全部取出到本地列表,快速释放队列
  4101. var batch = new List<MessageStruct>();
  4102. while (_messageQueue.TryDequeue(out var item))
  4103. batch.Add(item);
  4104. if (batch.Count == 0) return;
  4105. App.Current.Dispatcher.BeginInvoke(new Action(() =>
  4106. {
  4107. for (int i = 0; i < batch.Count; i++)
  4108. {
  4109. _eventAggregator.GetEvent<TaskMessageNotification>().Publish(batch[i]);
  4110. }
  4111. }), System.Windows.Threading.DispatcherPriority.Background);
  4112. }
  4113. public bool concurrenty = true;
  4114. public void CurrentRunStatus()
  4115. {
  4116. if (!concurrenty)
  4117. {
  4118. return;
  4119. }
  4120. concurrenty = false;
  4121. bool connectStaus = true;
  4122. bool mesStatus = true;
  4123. bool paraStatus = true;
  4124. try
  4125. {
  4126. var stationConfig = _configService.GetDeviceInfo(0);
  4127. if (!stationConfig.EnableMES || !stationConfig.EnableDoubleMes || !stationConfig.SaveCsv)
  4128. {
  4129. mesStatus = false;
  4130. }
  4131. foreach (var item in Status)
  4132. {
  4133. if (item.Background == System.Windows.Media.Brushes.Red)
  4134. {
  4135. connectStaus = false;
  4136. break;
  4137. }
  4138. }
  4139. }
  4140. catch (Exception)
  4141. {
  4142. connectStaus = false;
  4143. }
  4144. var curUser = _systemDatabaseService.GetCurrentUser();
  4145. if (connectStaus && mesStatus && _LastAutoRunning && curUser.userPart == UserPart.Operator)
  4146. {
  4147. CurrentDisplayMode = RunDisplayMode.Auto;
  4148. SendTaskMessage("当前为运行模式", MessageLevel.Info);
  4149. }
  4150. else
  4151. {
  4152. CurrentDisplayMode = RunDisplayMode.Manual;
  4153. SendTaskMessage("当前为调机模式", MessageLevel.Info);
  4154. }
  4155. concurrenty = true;
  4156. }
  4157. #region 键盘相邻关系
  4158. /// <summary>
  4159. /// 校验键盘所有按键值,相邻差值不能大于 0.3
  4160. /// </summary>
  4161. public bool CheckKeyBoardValue(ConcurrentDictionary<string, double> keyDic, string name, out string errorMsg)
  4162. {
  4163. errorMsg = "";
  4164. try
  4165. {
  4166. // 2. 获取每个按键的【真实相邻按键】
  4167. Dictionary<string, List<string>> neighborMap = GetUSKeyboardNeighborMap();
  4168. if (name.Contains("US"))
  4169. {
  4170. neighborMap = GetUSKeyboardNeighborMap();
  4171. }
  4172. else if (name.Contains("UK"))
  4173. {
  4174. neighborMap = GetUKKeyboardNeighborMap();
  4175. }
  4176. else if (name.Contains("JP"))
  4177. {
  4178. neighborMap = GetJPKeyboardNeighborMap();
  4179. }
  4180. else if (name.Contains("BZ"))
  4181. {
  4182. neighborMap = GetBZKeyboardNeighborMap();
  4183. }
  4184. else
  4185. {
  4186. SendTaskMessage("未查找到当前产品名称的键盘相邻关系", MessageLevel.Error);
  4187. }
  4188. // 3. 开始校验:每个按键 和 相邻按键 差值 ≤0.3
  4189. foreach (var item in keyDic)
  4190. {
  4191. string key = item.Key.ToUpper();
  4192. double val = item.Value;
  4193. // 没有相邻关系就跳过
  4194. if (!neighborMap.ContainsKey(key))
  4195. continue;
  4196. // 遍历所有相邻按键
  4197. foreach (string neighbor in neighborMap[key])
  4198. {
  4199. string n = neighbor.ToUpper();
  4200. if (!keyDic.ContainsKey(n))
  4201. continue;
  4202. double nVal = keyDic[n];
  4203. double diff = Math.Abs(val - nVal);
  4204. // 超过 0.3 直接报错
  4205. if (diff > 0.3)
  4206. {
  4207. SendTaskMessage($"按键 {key}({val}) 与相邻按键 {n}({nVal}) 差值 {diff:F3} > 0.3,校验不通过", MessageLevel.Error);
  4208. return false;
  4209. }
  4210. }
  4211. }
  4212. SendTaskMessage("所有键盘按键相邻差值校验通过", MessageLevel.Debug);
  4213. return true;
  4214. }
  4215. catch (Exception ex)
  4216. {
  4217. errorMsg = "校验异常:" + ex.Message;
  4218. return false;
  4219. }
  4220. }
  4221. /// <summary>
  4222. /// 键盘相邻关系-US
  4223. /// </summary>
  4224. private Dictionary<string, List<string>> GetUSKeyboardNeighborMap()
  4225. {
  4226. #region 以前的键盘相邻关系-US
  4227. //return new Dictionary<string, List<string>>
  4228. //{
  4229. // // ==============================================
  4230. // // 第一行:ESC + F1~F12
  4231. // // ==============================================
  4232. // ["ESC"] = new List<string> { "F1", "~", },
  4233. // ["F1"] = new List<string> { "ESC", "F2", "1" },
  4234. // ["F2"] = new List<string> { "F1", "F3", "2" },
  4235. // ["F3"] = new List<string> { "F2", "F4", "2", "3" },
  4236. // ["F4"] = new List<string> { "F3", "F5", "3", "4" },
  4237. // ["F5"] = new List<string> { "F4", "F6", "4", "5" },
  4238. // ["F6"] = new List<string> { "F5", "F7", "5", "6" },
  4239. // ["F7"] = new List<string> { "F6", "F8", "6", "7" },
  4240. // ["F8"] = new List<string> { "F7", "F9", "7", "8" },
  4241. // ["F9"] = new List<string> { "F8", "F10", "8", "9" },
  4242. // ["F10"] = new List<string> { "F9", "F11", "9", "0" },
  4243. // ["F11"] = new List<string> { "F10", "F12", "0", "-" },
  4244. // ["F12"] = new List<string> { "F11", "-", "=", "Insert" },
  4245. // ["Insert"] = new List<string> { "F12", "Power", "Backspace" },
  4246. // ["Power"] = new List<string> { "Backspace" },
  4247. // // ==============================================
  4248. // // 第二行:` 1 2 3 4 5 6 7 8 9 0 - = Backspace
  4249. // // ==============================================
  4250. // ["~"] = new List<string> { "ESC", "1", "TAB" },
  4251. // ["1"] = new List<string> { "F1", "`", "2", "TAB", "Q" },
  4252. // ["2"] = new List<string> { "F2", "1", "3", "Q", "W" },
  4253. // ["3"] = new List<string> { "F3", "F4", "2", "4", "W", "E" },
  4254. // ["4"] = new List<string> { "F4", "F5", "3", "5", "E", "R" },
  4255. // ["5"] = new List<string> { "F5", "F6", "4", "6", "R", "T" },
  4256. // ["6"] = new List<string> { "F6", "F7", "5", "7", "T", "Y" },
  4257. // ["7"] = new List<string> { "F7", "F8", "6", "8", "Y", "U" },
  4258. // ["8"] = new List<string> { "F8", "F9", "7", "9", "U", "I" },
  4259. // ["9"] = new List<string> { "F9", "F10", "8", "0", "I", "O" },
  4260. // ["0"] = new List<string> { "F10", "F11", "9", "-", "O", "P" },
  4261. // ["-"] = new List<string> { "F11", "F12", "0", "=", "P", "{" },
  4262. // ["="] = new List<string> { "F12", "-", "Backspace", "{", "}" },
  4263. // ["Backspace"] = new List<string> { "Insert", "=", "}", "|", "Power" },
  4264. // // ==============================================
  4265. // // 第三行:TAB Q W E R T Y U I O P [ ] \
  4266. // // ==============================================
  4267. // ["TAB"] = new List<string> { "`", "1", "Q", "CapsLock" },
  4268. // ["Q"] = new List<string> { "TAB", "`", "1", "2", "W", "A", "CapsLock" },
  4269. // ["W"] = new List<string> { "Q", "1", "2", "3", "E", "A", "S" },
  4270. // ["E"] = new List<string> { "W", "2", "3", "4", "R", "S", "D" },
  4271. // ["R"] = new List<string> { "E", "3", "4", "5", "T", "D", "F" },
  4272. // ["T"] = new List<string> { "R", "4", "5", "6", "Y", "F", "G" },
  4273. // ["Y"] = new List<string> { "T", "5", "6", "7", "U", "G", "H" },
  4274. // ["U"] = new List<string> { "Y", "6", "7", "8", "I", "H", "J" },
  4275. // ["I"] = new List<string> { "U", "7", "8", "9", "O", "J", "K" },
  4276. // ["O"] = new List<string> { "I", "8", "9", "0", "P", "K", "L" },
  4277. // ["P"] = new List<string> { "O", "9", "0", "-", "{", "L", ";" },
  4278. // ["{"] = new List<string> { "P", "0", "-", "=", "}", ";", "'" },
  4279. // ["}"] = new List<string> { "{", "-", "=", "Backspace", "|", "'", "Enter" },
  4280. // ["|"] = new List<string> { "}", "Backspace", "Enter" },
  4281. // // ==============================================
  4282. // // 第四行:CapsLock A S D F G H J K L ; ' Enter
  4283. // // ==============================================
  4284. // ["CapsLock"] = new List<string> { "TAB", "Q", "A", "LeftShift" },
  4285. // ["A"] = new List<string> { "CapsLock", "Q", "W", "S", "LeftShift", "Z" },
  4286. // ["S"] = new List<string> { "A", "W", "E", "D", "Z", "X", "LeftShift" },
  4287. // ["D"] = new List<string> { "S", "E", "R", "F", "X", "C", "LeftShift" },
  4288. // ["F"] = new List<string> { "D", "R", "T", "G", "C", "V" },
  4289. // ["G"] = new List<string> { "F", "T", "Y", "H", "V", "B" },
  4290. // ["H"] = new List<string> { "G", "Y", "U", "J", "B", "N" },
  4291. // ["J"] = new List<string> { "H", "U", "I", "K", "N", "M" },
  4292. // ["K"] = new List<string> { "J", "I", "O", "L", "M", "," },
  4293. // ["L"] = new List<string> { "K", "O", "P", ";", "<", ">", "?" },
  4294. // [";"] = new List<string> { "L", "P", "{", "'", ">", "?" },
  4295. // ["'"] = new List<string> { ";", "{", "}", "Enter", "?" },
  4296. // ["Enter"] = new List<string> { "'", "}", "|", "RightShift" },
  4297. // // ==============================================
  4298. // // 第五行:LeftShift Z X C V B N M , . / RightShift
  4299. // // ==============================================
  4300. // ["Shift"] = new List<string> { "CapsLock", "A", "S", "D", "Z", "Ctrl", "Fn" },
  4301. // ["Z"] = new List<string> { "Shift", "A", "S", "X" },
  4302. // ["X"] = new List<string> { "Z", "S", "D", "C" },
  4303. // ["C"] = new List<string> { "X", "D", "F", "V" },
  4304. // ["V"] = new List<string> { "C", "F", "G", "B" },
  4305. // ["B"] = new List<string> { "V", "G", "H", "N" },
  4306. // ["N"] = new List<string> { "B", "H", "J", "M" },
  4307. // ["M"] = new List<string> { "N", "J", "K", "<" },
  4308. // ["<"] = new List<string> { "M", "K", "L", ">" },
  4309. // [">"] = new List<string> { "<", "L", ";", "?" },
  4310. // ["?"] = new List<string> { ">", ";", "'", "Shift2" },
  4311. // ["Shift2"] = new List<string> { "?", "Enter" },
  4312. // // ==============================================
  4313. // // 第六行:Ctrl Fn Win Alt Space Alt Fn Ctrl ← ↓ →
  4314. // // ==============================================
  4315. // ["Ctrl1"] = new List<string> { "Fn", "Shift" },
  4316. // ["Fn"] = new List<string> { "Ctrl", "Win", "Shift" },
  4317. // ["Win"] = new List<string> { "Fn", "Alt" },
  4318. // ["Alt1"] = new List<string> { "Win", "Space" },
  4319. // ["Space1"] = new List<string> { "Alt", "Alt2" },
  4320. // ["Alt2"] = new List<string> { "Space", "Ctrl2" },
  4321. // // ["RightFn"] = new List<string> { "RightAlt", "RightCtrl" },
  4322. // ["Ctrl2"] = new List<string> { "Alt2", "Left", "Updown", "Right" },
  4323. // ["Left"] = new List<string> { "RightCtrl", "Updown" },
  4324. // ["Updown"] = new List<string> { "Left", "Right", "Ctrl2" },
  4325. // ["Right"] = new List<string> { "Updown", "Ctrl2" }
  4326. //};
  4327. #endregion
  4328. return new Dictionary<string, List<string>>
  4329. {
  4330. // ==============================================
  4331. // 第一行:110 + 112~113
  4332. // ==============================================
  4333. ["110"] = new List<string> { "112", "1", },
  4334. ["112"] = new List<string> { "110", "113", "2" },
  4335. ["113"] = new List<string> { "112", "114", "3" },
  4336. ["114"] = new List<string> { "113", "115", "4" },
  4337. ["115"] = new List<string> { "114", "116", "5" },
  4338. ["116"] = new List<string> { "115", "117", "6" },
  4339. ["117"] = new List<string> { "116", "118", "7" },
  4340. ["118"] = new List<string> { "117", "119", "8" },
  4341. ["119"] = new List<string> { "118", "120", "8" },
  4342. ["120"] = new List<string> { "119", "121", "9" },
  4343. ["121"] = new List<string> { "120", "122", "10" },
  4344. ["122"] = new List<string> { "121", "123", "11" },
  4345. ["123"] = new List<string> { "122", "75", "12" },
  4346. ["75"] = new List<string> { "123", "76", "13" },
  4347. ["76"] = new List<string> { "75", "PWB", "15" },
  4348. ["PWB"] = new List<string> { "76", "15" },
  4349. // ==============================================
  4350. // 第二行:` 1 2 3 4 5 6 7 8 9 10 11 12 13 15
  4351. // ==============================================
  4352. ["1"] = new List<string> { "110", "2", "16" },
  4353. ["2"] = new List<string> { "112", "1", "3", "16" },
  4354. ["3"] = new List<string> { "113", "2", "4", "17" },
  4355. ["4"] = new List<string> { "114", "3", "5", "19" },
  4356. ["5"] = new List<string> { "115", "4", "6", "20" },
  4357. ["6"] = new List<string> { "116", "5", "7", "21" },
  4358. ["7"] = new List<string> { "117", "6", "8", "22" },
  4359. ["8"] = new List<string> { "118", "7", "9", "23" },
  4360. ["9"] = new List<string> { "120", "8", "10", "24" },
  4361. ["10"] = new List<string> { "121", "9", "11", "25" },
  4362. ["11"] = new List<string> { "122", "10", "12", "26" },
  4363. ["12"] = new List<string> { "123", "11", "13", "27" },
  4364. ["13"] = new List<string> { "75", "12", "15", "28" },
  4365. ["15"] = new List<string> { "76", "13", "29" },
  4366. // ==============================================
  4367. // 第三行:16 17 18 19 20 21 22 23 24 25 26 27 28 29
  4368. // ==============================================
  4369. ["16"] = new List<string> { "1", "17", "30" },
  4370. ["17"] = new List<string> { "3", "16", "18", "31" },
  4371. ["18"] = new List<string> { "3", "17", "19", "32" },
  4372. ["19"] = new List<string> { "4", "18", "20", "33" },
  4373. ["20"] = new List<string> { "5", "19", "21", "34" },
  4374. ["21"] = new List<string> { "6", "20", "22", "35" },
  4375. ["22"] = new List<string> { "7", "21", "23", "36" },
  4376. ["23"] = new List<string> { "8", "22", "24", "37" },
  4377. ["24"] = new List<string> { "9", "23", "25", "38" },
  4378. ["25"] = new List<string> { "10", "24", "26", "39" },
  4379. ["26"] = new List<string> { "11", "25", "27", "40" },
  4380. ["27"] = new List<string> { "12", "26", "28", "41" },
  4381. ["28"] = new List<string> { "13", "27", "29", "43" },
  4382. ["29"] = new List<string> { "15", "28", "43" },
  4383. // ==============================================
  4384. // 第四行:30 31 32 33 34 35 36 37 38 39 40 41 43
  4385. // ==============================================
  4386. ["30"] = new List<string> { "16", "31", "44" },
  4387. ["31"] = new List<string> { "17", "30", "32", "46" },
  4388. ["32"] = new List<string> { "18", "31", "33", "47" },
  4389. ["33"] = new List<string> { "19", "32", "34", "48" },
  4390. ["34"] = new List<string> { "20", "33", "35", "49" },
  4391. ["35"] = new List<string> { "21", "34", "36", "50" },
  4392. ["36"] = new List<string> { "22", "35", "37", "51" },
  4393. ["37"] = new List<string> { "23", "36", "38", "52" },
  4394. ["38"] = new List<string> { "24", "37", "39", "53" },
  4395. ["39"] = new List<string> { "25", "38", "40", "54" },
  4396. ["40"] = new List<string> { "26", "39", "41", "55" },
  4397. ["41"] = new List<string> { "27", "40", "43", "55" },
  4398. ["43"] = new List<string> { "29", "41", "57" },
  4399. // ==============================================
  4400. // 第五行:44 46 47 48 49 50 51 52 53 54 55 57
  4401. // ==============================================
  4402. ["44"] = new List<string> { "30", "46", "58" },
  4403. ["46"] = new List<string> { "31", "44", "47", "127" },
  4404. ["47"] = new List<string> { "32", "46", "48", "60" },
  4405. ["48"] = new List<string> { "33", "47", "49", "61_1" },
  4406. ["49"] = new List<string> { "34", "48", "50", "61_1" },
  4407. ["50"] = new List<string> { "35", "49", "51", "61_1" },
  4408. ["51"] = new List<string> { "36", "50", "52", "61_2" },
  4409. ["52"] = new List<string> { "37", "51", "53", "61_2" },
  4410. ["53"] = new List<string> { "38", "52", "54", "62" },
  4411. ["54"] = new List<string> { "39", "53", "55", "64" },
  4412. ["55"] = new List<string> { "40", "54", "57", "79" },
  4413. ["57"] = new List<string> { "43", "55", "89" },
  4414. // ==============================================
  4415. // 第六行:58 59 127 60 61_1 61_2 62 64 83_84 89
  4416. // ==============================================
  4417. ["58"] = new List<string> { "44", "59" },
  4418. ["59"] = new List<string> { "44", "58", "60" },
  4419. ["127"] = new List<string> { "46", "59", "60" },
  4420. ["60"] = new List<string> { "47", "127", "61_1" },
  4421. ["61_1"] = new List<string> { "49", "60" },
  4422. ["61_2"] = new List<string> { "51", "62" },
  4423. // ["RightFn"] = new List<string> { "RightAlt", "RightCtrl" },
  4424. ["62"] = new List<string> { "53", "61_2", "64" },
  4425. ["64"] = new List<string> { "54", "62", "79" },
  4426. ["79"] = new List<string> { "55", "64", "83_84" },
  4427. ["83_84"] = new List<string> { "57", "79", "89" },
  4428. ["89"] = new List<string> { "57", "83_84" }
  4429. };
  4430. }
  4431. /// <summary>
  4432. /// UK欧版键盘相邻关系
  4433. /// </summary>
  4434. private Dictionary<string, List<string>> GetUKKeyboardNeighborMap()
  4435. {
  4436. #region 以前的键盘相邻关系-UK
  4437. //return new Dictionary<string, List<string>>
  4438. //{
  4439. // // ==============================================
  4440. // // 第一行:Esc F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 Insert delete Power
  4441. // // ==============================================
  4442. // ["Esc"] = new List<string> { "F1", "`" },
  4443. // ["F1"] = new List<string> { "Esc", "F2", "`", "1" },
  4444. // ["F2"] = new List<string> { "F1", "F3", "1", "2" },
  4445. // ["F3"] = new List<string> { "F2", "F4", "2", "3" },
  4446. // ["F4"] = new List<string> { "F3", "F5", "3", "4" },
  4447. // ["F5"] = new List<string> { "F4", "F6", "4", "5" },
  4448. // ["F6"] = new List<string> { "F5", "F7", "5", "6" },
  4449. // ["F7"] = new List<string> { "F6", "F8", "6", "7" },
  4450. // ["F8"] = new List<string> { "F7", "F9", "7", "8" },
  4451. // ["F9"] = new List<string> { "F8", "F10", "8", "9" },
  4452. // ["F10"] = new List<string> { "F9", "F11", "9", "0" },
  4453. // ["F11"] = new List<string> { "F10", "F12", "0", "-" },
  4454. // ["F12"] = new List<string> { "F11", "Insert", "-", "=" },
  4455. // ["Insert"] = new List<string> { "F12", "Delete", "=", "backspace" },
  4456. // ["Delete"] = new List<string> { "Insert", "backspace" },
  4457. // // ==============================================
  4458. // // 第二行 、1 2 3 4 5 6 7 8 9 0 _ = Backspace
  4459. // // ==============================================
  4460. // ["`"] = new List<string> { "Esc", "F1", "1", "Tab" },
  4461. // ["1"] = new List<string> { "`", "F1", "F2", "2", "Tab", "Q" },
  4462. // ["2"] = new List<string> { "1", "F2", "F3", "3", "Q", "W" },
  4463. // ["3"] = new List<string> { "2", "F3", "F4", "4", "W", "E" },
  4464. // ["4"] = new List<string> { "3", "F4", "F5", "5", "E", "R" },
  4465. // ["5"] = new List<string> { "4", "F5", "F6", "6", "R", "T" },
  4466. // ["6"] = new List<string> { "5", "F6", "F7", "7", "T", "Y" },
  4467. // ["7"] = new List<string> { "6", "F7", "F8", "8", "Y", "U" },
  4468. // ["8"] = new List<string> { "7", "F8", "F9", "9", "U", "I" },
  4469. // ["9"] = new List<string> { "8", "F9", "F10", "0", "I", "O" },
  4470. // ["0"] = new List<string> { "9", "F10", "F11", "-", "O", "P" },
  4471. // ["-"] = new List<string> { "0", "F11", "F12", "=", "P", "[" },
  4472. // ["="] = new List<string> { "-", "F12", "Insert", "backspace", "[", "]" },
  4473. // ["backspace"] = new List<string> { "=", "Insert", "Delete", "]" },
  4474. // // ==============================================
  4475. // // 第三行 Tab Q W E R T Y U I O P { }
  4476. // // ==============================================
  4477. // ["Tab"] = new List<string> { "`", "1", "Q", "capslock" },
  4478. // ["Q"] = new List<string> { "tab", "1", "2", "W", "capslock", "A" },
  4479. // ["W"] = new List<string> { "Q", "2", "3", "E", "A", "S" },
  4480. // ["E"] = new List<string> { "W", "3", "4", "R", "S", "D" },
  4481. // ["R"] = new List<string> { "E", "4", "5", "T", "D", "F" },
  4482. // ["T"] = new List<string> { "R", "5", "6", "Y", "F", "G" },
  4483. // ["Y"] = new List<string> { "T", "6", "7", "U", "G", "H" },
  4484. // ["U"] = new List<string> { "Y", "7", "8", "I", "H", "J" },
  4485. // ["I"] = new List<string> { "U", "8", "9", "O", "J", "K" },
  4486. // ["O"] = new List<string> { "I", "9", "0", "P", "K", "L" },
  4487. // ["P"] = new List<string> { "O", "0", "-", "{", "L", ";" },
  4488. // ["{"] = new List<string> { "P", "-", "=", "}", ";", "@" },
  4489. // ["}"] = new List<string> { "[", "=", "backspace", "@", "Enter" },
  4490. // // ==============================================
  4491. // // 第四行 CapsLock A S D F G H J K L : ` ~ Enter
  4492. // // ==============================================
  4493. // ["capslock"] = new List<string> { "Tab", "Q", "A", "Shift1" },
  4494. // ["A"] = new List<string> { "capslock", "Q", "W", "S", "Shift1", "|" },
  4495. // ["S"] = new List<string> { "A", "W", "E", "D", "|", "X" },
  4496. // ["D"] = new List<string> { "S", "E", "R", "F", "X", "C" },
  4497. // ["F"] = new List<string> { "D", "R", "T", "G", "C", "V" },
  4498. // ["G"] = new List<string> { "F", "T", "Y", "H", "V", "B" },
  4499. // ["H"] = new List<string> { "G", "Y", "U", "J", "B", "N" },
  4500. // ["J"] = new List<string> { "H", "U", "I", "K", "N", "M" },
  4501. // ["K"] = new List<string> { "J", "I", "O", "L", "M", "<" },
  4502. // ["L"] = new List<string> { "K", "O", "P", ";", "<", ">" },
  4503. // [";"] = new List<string> { "L", "P", "{", "@", ">", "?" },
  4504. // ["@"] = new List<string> { ";", "{", "}", "Enter", "?", "#" },
  4505. // ["#"] = new List<string> { "@", "Enter", "Shift2" },
  4506. // ["Enter"] = new List<string> { "@", "}", "#", "Shift2" },
  4507. // // ==============================================
  4508. // // 第五行 Shift1 \ Z X C V B N M < > ? Shift2
  4509. // // ==============================================
  4510. // ["Shift1"] = new List<string> { "capslock", "A", "|", "Ctrl1" },
  4511. // ["|"] = new List<string> { "Shift1", "A", "S", "X", "Ctrl1", "Fn" },
  4512. // ["Z"] = new List<string> { "|", "S", "X" },
  4513. // ["X"] = new List<string> { "|", "S", "D", "C", "Fn", "Win" },
  4514. // ["C"] = new List<string> { "X", "D", "F", "V", "Win", "Alt1" },
  4515. // ["V"] = new List<string> { "C", "F", "G", "B", "Alt1", "space" },
  4516. // ["B"] = new List<string> { "V", "G", "H", "N", "space", "altgr" },
  4517. // ["N"] = new List<string> { "B", "H", "J", "M", "altgr", "Ctrl2" },
  4518. // ["M"] = new List<string> { "N", "J", "K", "<", "Ctrl2", "Left" },
  4519. // ["<"] = new List<string> { "M", "K", "L", ">", "Left", "UpDown" },
  4520. // [">"] = new List<string> { "<", "L", ";", "?", "UpDown", "Right" },
  4521. // ["?"] = new List<string> { ">", ";", "@", "#", "Shift2", "Right" },
  4522. // ["Shift2"] = new List<string> { "?", "#", "Enter" },
  4523. // // ==============================================
  4524. // // 第六行 Ctrl1 fn Win Alt1 Space1 Space2 Alt2 Ctrl2 Left UpDown Right
  4525. // // ==============================================
  4526. // ["Ctrl1"] = new List<string> { "Shift1", "|", "Fn" },
  4527. // ["Fn"] = new List<string> { "Ctrl1", "|", "X", "Win" },
  4528. // ["Win"] = new List<string> { "Fn", "X", "C", "Alt1" },
  4529. // ["Alt1"] = new List<string> { "Win", "C", "V", "space" },
  4530. // ["space"] = new List<string> { "Alt1", "V", "B", "altgr" },
  4531. // ["altgr"] = new List<string> { "space", "B", "N", "Ctrl2" },
  4532. // ["Ctrl2"] = new List<string> { "altgr", "N", "M", "Left" },
  4533. // ["Left"] = new List<string> { "Ctrl2", "M", ",", "UpDown" },
  4534. // ["UpDown"] = new List<string> { "Left", ",", ".", "Right" },
  4535. // ["Right"] = new List<string> { "UpDown", ".", "?" }
  4536. //};
  4537. #endregion
  4538. return new Dictionary<string, List<string>>
  4539. {
  4540. // ==============================================
  4541. // 第一行:110 + 112~113
  4542. // ==============================================
  4543. ["110"] = new List<string> { "112", "1", },
  4544. ["112"] = new List<string> { "110", "113", "2" },
  4545. ["113"] = new List<string> { "112", "114", "3" },
  4546. ["114"] = new List<string> { "113", "115", "4" },
  4547. ["115"] = new List<string> { "114", "116", "5" },
  4548. ["116"] = new List<string> { "115", "117", "6" },
  4549. ["117"] = new List<string> { "116", "118", "7" },
  4550. ["118"] = new List<string> { "117", "119", "8" },
  4551. ["119"] = new List<string> { "118", "120", "8" },
  4552. ["120"] = new List<string> { "119", "121", "9" },
  4553. ["121"] = new List<string> { "120", "122", "10" },
  4554. ["122"] = new List<string> { "121", "123", "11" },
  4555. ["123"] = new List<string> { "122", "75", "12" },
  4556. ["75"] = new List<string> { "123", "76", "13" },
  4557. ["76"] = new List<string> { "75", "PWB", "15" },
  4558. ["PWB"] = new List<string> { "76", "15" },
  4559. // ==============================================
  4560. // 第二行:` 1 2 3 4 5 6 7 8 9 10 11 12 13 15
  4561. // ==============================================
  4562. ["1"] = new List<string> { "110", "2", "16" },
  4563. ["2"] = new List<string> { "112", "1", "3", "16" },
  4564. ["3"] = new List<string> { "113", "2", "4", "17" },
  4565. ["4"] = new List<string> { "114", "3", "5", "19" },
  4566. ["5"] = new List<string> { "115", "4", "6", "20" },
  4567. ["6"] = new List<string> { "116", "5", "7", "21" },
  4568. ["7"] = new List<string> { "117", "6", "8", "22" },
  4569. ["8"] = new List<string> { "118", "7", "9", "23" },
  4570. ["9"] = new List<string> { "120", "8", "10", "24" },
  4571. ["10"] = new List<string> { "121", "9", "11", "25" },
  4572. ["11"] = new List<string> { "122", "10", "12", "26" },
  4573. ["12"] = new List<string> { "123", "11", "13", "27" },
  4574. ["13"] = new List<string> { "75", "12", "15", "28" },
  4575. ["15"] = new List<string> { "76", "13", "29" },
  4576. // ==============================================
  4577. // 第三行:16 17 18 19 20 21 22 23 24 25 26 27 28 43
  4578. // ==============================================
  4579. ["16"] = new List<string> { "1", "17", "30" },
  4580. ["17"] = new List<string> { "3", "16", "18", "31" },
  4581. ["18"] = new List<string> { "3", "17", "19", "32" },
  4582. ["19"] = new List<string> { "4", "18", "20", "33" },
  4583. ["20"] = new List<string> { "5", "19", "21", "34" },
  4584. ["21"] = new List<string> { "6", "20", "22", "35" },
  4585. ["22"] = new List<string> { "7", "21", "23", "36" },
  4586. ["23"] = new List<string> { "8", "22", "24", "37" },
  4587. ["24"] = new List<string> { "9", "23", "25", "38" },
  4588. ["25"] = new List<string> { "10", "24", "26", "39" },
  4589. ["26"] = new List<string> { "11", "25", "27", "40" },
  4590. ["27"] = new List<string> { "12", "26", "28", "41" },
  4591. ["28"] = new List<string> { "13", "27", "29", "43" },
  4592. ["43"] = new List<string> { "15", "28", "42", "57" },
  4593. // ==============================================
  4594. // 第四行:30 31 32 33 34 35 36 37 38 39 40 41 42
  4595. // ==============================================
  4596. ["30"] = new List<string> { "16", "31", "44" },
  4597. ["31"] = new List<string> { "17", "30", "32", "46" },
  4598. ["32"] = new List<string> { "18", "31", "33", "47" },
  4599. ["33"] = new List<string> { "19", "32", "34", "48" },
  4600. ["34"] = new List<string> { "20", "33", "35", "49" },
  4601. ["35"] = new List<string> { "21", "34", "36", "50" },
  4602. ["36"] = new List<string> { "22", "35", "37", "51" },
  4603. ["37"] = new List<string> { "23", "36", "38", "52" },
  4604. ["38"] = new List<string> { "24", "37", "39", "53" },
  4605. ["39"] = new List<string> { "25", "38", "40", "54" },
  4606. ["40"] = new List<string> { "26", "39", "41", "55" },
  4607. ["41"] = new List<string> { "27", "40", "43", "55" },
  4608. ["42"] = new List<string> { "28", "41", "57" },
  4609. // ==============================================
  4610. // 第五行:44 46 47 48 49 50 51 52 53 54 55 57
  4611. // ==============================================
  4612. ["44"] = new List<string> { "30", "45", "58" },
  4613. ["45"] = new List<string> { "30", "44", "46", "59" },
  4614. ["46"] = new List<string> { "31", "44", "47", "127" },
  4615. ["47"] = new List<string> { "32", "46", "48", "60" },
  4616. ["48"] = new List<string> { "33", "47", "49", "61_1" },
  4617. ["49"] = new List<string> { "34", "48", "50", "61_1" },
  4618. ["50"] = new List<string> { "35", "49", "51", "61_1" },
  4619. ["51"] = new List<string> { "36", "50", "52", "61_2" },
  4620. ["52"] = new List<string> { "37", "51", "53", "61_2" },
  4621. ["53"] = new List<string> { "38", "52", "54", "62" },
  4622. ["54"] = new List<string> { "39", "53", "55", "64" },
  4623. ["55"] = new List<string> { "40", "54", "57", "79" },
  4624. ["57"] = new List<string> { "43", "55", "89" },
  4625. // ==============================================
  4626. // 第六行:58 59 127 60 61_1 61_2 62 64 83_84 89
  4627. // ==============================================
  4628. ["58"] = new List<string> { "44", "59" },
  4629. ["59"] = new List<string> { "44", "58", "60" },
  4630. ["127"] = new List<string> { "46", "59", "60" },
  4631. ["60"] = new List<string> { "47", "127", "61_1" },
  4632. ["61_1"] = new List<string> { "49", "60" },
  4633. ["61_2"] = new List<string> { "51", "62" },
  4634. // ["RightFn"] = new List<string> { "RightAlt", "RightCtrl" },
  4635. ["62"] = new List<string> { "53", "61_2", "64" },
  4636. ["64"] = new List<string> { "54", "62", "79" },
  4637. ["79"] = new List<string> { "55", "64", "83_84" },
  4638. ["83_84"] = new List<string> { "57", "79", "89" },
  4639. ["89"] = new List<string> { "57", "83_84" }
  4640. };
  4641. }
  4642. /// <summary>
  4643. /// 日文JP键盘相邻关系
  4644. /// </summary>
  4645. private Dictionary<string, List<string>> GetJPKeyboardNeighborMap()
  4646. {
  4647. #region 之前的JP
  4648. //return new Dictionary<string, List<string>>
  4649. //{
  4650. // // ==============================================
  4651. // // 第一行:Esc F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 Insert Delete Power
  4652. // // ==============================================
  4653. // ["Esc"] = new List<string> { "F1", "/" },
  4654. // ["F1"] = new List<string> { "Esc", "F2", "/" },
  4655. // ["F2"] = new List<string> { "F1", "F3", "1" },
  4656. // ["F3"] = new List<string> { "F2", "F4", "2" },
  4657. // ["F4"] = new List<string> { "F3", "F5", "3" },
  4658. // ["F5"] = new List<string> { "F4", "F6", "4" },
  4659. // ["F6"] = new List<string> { "F5", "F7", "5" },
  4660. // ["F7"] = new List<string> { "F6", "F8", "6" },
  4661. // ["F8"] = new List<string> { "F7", "F9", "7" },
  4662. // ["F9"] = new List<string> { "F8", "F10", "8" },
  4663. // ["F10"] = new List<string> { "F9", "F11", "9" },
  4664. // ["F11"] = new List<string> { "F10", "F12", "0" },
  4665. // ["F12"] = new List<string> { "F11", "insert", "=" },
  4666. // ["insert"] = new List<string> { "F12", "delete", "~" },
  4667. // ["delete"] = new List<string> { "insert", "|" },
  4668. // ["Power"] = new List<string> { "insert", "|" },
  4669. // // ==============================================
  4670. // // 第二行 / 1 2 3 4 5 6 7 8 9 0 = ~ | backspace
  4671. // // ==============================================
  4672. // ["/"] = new List<string> { "Esc", "F1", "1", "tab" },
  4673. // ["1"] = new List<string> { "/", "F2", "2", "tab", "Q" },
  4674. // ["2"] = new List<string> { "1", "F3", "3", "Q", "W" },
  4675. // ["3"] = new List<string> { "2", "F4", "4", "W", "E" },
  4676. // ["4"] = new List<string> { "3", "F5", "5", "E", "R" },
  4677. // ["5"] = new List<string> { "4", "F6", "6", "R", "T" },
  4678. // ["6"] = new List<string> { "5", "F7", "7", "T", "Y" },
  4679. // ["7"] = new List<string> { "6", "F8", "8", "Y", "U" },
  4680. // ["8"] = new List<string> { "7", "F9", "9", "U", "I" },
  4681. // ["9"] = new List<string> { "8", "F10", "0", "I", "O" },
  4682. // ["0"] = new List<string> { "9", "F11", "=", "O", "P" },
  4683. // ["="] = new List<string> { "0", "F12", "~", "P", "@" },
  4684. // ["~"] = new List<string> { "=", "insert", "|", "@", "{" },
  4685. // ["|"] = new List<string> { "~", "delete", "backspace", "{" },
  4686. // ["backspace"] = new List<string> { "|", "}" },
  4687. // // ==============================================
  4688. // // 第三行 Tab Q W E R T Y U I O P @ {
  4689. // // ==============================================
  4690. // ["Tab"] = new List<string> { "1", "Q", "capslock" },
  4691. // ["Q"] = new List<string> { "Tab", "1", "2", "W", "capslock", "A" },
  4692. // ["W"] = new List<string> { "Q", "2", "3", "E", "A", "S" },
  4693. // ["E"] = new List<string> { "W", "3", "4", "R", "S", "D" },
  4694. // ["R"] = new List<string> { "E", "4", "5", "T", "D", "F" },
  4695. // ["T"] = new List<string> { "R", "5", "6", "Y", "F", "G" },
  4696. // ["Y"] = new List<string> { "T", "6", "7", "U", "G", "H" },
  4697. // ["U"] = new List<string> { "Y", "7", "8", "I", "H", "J" },
  4698. // ["I"] = new List<string> { "U", "8", "9", "O", "J", "K" },
  4699. // ["O"] = new List<string> { "I", "9", "0", "P", "K", "L" },
  4700. // ["P"] = new List<string> { "O", "0", "=", "@", "L", ";" },
  4701. // ["@"] = new List<string> { "P", "=", "~", "{", ";", ":" },
  4702. // ["{"] = new List<string> { "@", "~", "|", "backspace", ":", "}" },
  4703. // // ==============================================
  4704. // // 第四行 CapsLock A S D F G H J K L ; : } Enter
  4705. // // ==============================================
  4706. // ["CapsLock"] = new List<string> { "tab", "Q", "A", "shift1" },
  4707. // ["A"] = new List<string> { "CapsLock", "Q", "W", "S", "shift1", "Z" },
  4708. // ["S"] = new List<string> { "A", "W", "E", "D", "Z", "X" },
  4709. // ["D"] = new List<string> { "S", "E", "R", "F", "X", "C" },
  4710. // ["F"] = new List<string> { "D", "R", "T", "G", "C", "V" },
  4711. // ["G"] = new List<string> { "F", "T", "Y", "H", "V", "B" },
  4712. // ["H"] = new List<string> { "G", "Y", "U", "J", "B", "N" },
  4713. // ["J"] = new List<string> { "H", "U", "I", "K", "N", "M" },
  4714. // ["K"] = new List<string> { "J", "I", "O", "L", "M", "<" },
  4715. // ["L"] = new List<string> { "K", "O", "P", ";", "<", ">" },
  4716. // [";"] = new List<string> { "L", "P", "@", ":", ">", "?" },
  4717. // [":"] = new List<string> { ";", "@", "{", "}", "?", "\\" },
  4718. // ["}"] = new List<string> { ":", "{", "backspace", "Enter", "ろ", "Shift2" },
  4719. // ["Enter"] = new List<string> { "}", "Shift2" },
  4720. // // ==============================================
  4721. // // 第五行 Shift1 Z X C V B N M < > ? \ shift2
  4722. // // ==============================================
  4723. // ["shift1"] = new List<string> { "CapsLock", "A", "Z", "Ctrl1" },
  4724. // ["Z"] = new List<string> { "shift1", "A", "S", "X", "Ctrl1", "Fn" },
  4725. // ["X"] = new List<string> { "Z", "S", "D", "C", "Fn", "Win" },
  4726. // ["C"] = new List<string> { "X", "D", "F", "V", "Win", "Alt1" },
  4727. // ["V"] = new List<string> { "C", "F", "G", "B", "Alt1", "变换" },
  4728. // ["B"] = new List<string> { "V", "G", "H", "N", "无变换", "Space1" },
  4729. // ["N"] = new List<string> { "B", "H", "J", "M", "Space1", "Space2" },
  4730. // ["M"] = new List<string> { "N", "J", "K", "<", "Space2", "变换" },
  4731. // ["<"] = new List<string> { "M", "K", "L", ">", "变换", "口" },
  4732. // [">"] = new List<string> { "<", "L", ";", "?", "口", "Left" },
  4733. // ["?"] = new List<string> { ">", ";", ":", "\\", "Left", "UpDown" },
  4734. // ["\\"] = new List<string> { "?", ":", "}", "Shift2", "UpDown", "Right" },
  4735. // ["Shift2"] = new List<string> { "\\", "}", "Enter", "Right" },
  4736. // // ==============================================
  4737. // // 第六行 Ctrl1 fn Win Alt1 无变换 Space1 Space2 变换 口 Ctrl2 Left Updown Right
  4738. // // ==============================================
  4739. // ["Ctrl1"] = new List<string> { "shift1", "Z", "Fn" },
  4740. // ["Fn"] = new List<string> { "Ctrl1", "Z", "X", "Win" },
  4741. // ["Win"] = new List<string> { "Fn", "X", "C", "Alt1" },
  4742. // ["Alt1"] = new List<string> { "Win", "C", "V", "无变换" },
  4743. // ["无变换"] = new List<string> { "Alt1", "V", "B", "Space1" },
  4744. // ["Space1"] = new List<string> { "无变换", "B", "N", "Space2" },
  4745. // ["变换"] = new List<string> { "Space2", "M", ",", "口" },
  4746. // ["口"] = new List<string> { "变换", ",", ">", "Left" },
  4747. // ["Ctrl2"] = new List<string> { "Left", ">", "?", "口" },
  4748. // ["Left"] = new List<string> { "口", ">", "?", "UpDown" },
  4749. // ["UpDown"] = new List<string> { "Left", "?", "\\", "Right" },
  4750. // ["Right"] = new List<string> { "UpDown", "\\", "Shift2" }
  4751. //};
  4752. //return new Dictionary<string, List<string>>
  4753. //{
  4754. // // ==============================================
  4755. // // 第一行:Esc F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 Insert Delete Power
  4756. // // ==============================================
  4757. // ["Esc"] = new List<string> { "F1", "/" },
  4758. // ["F1"] = new List<string> { "Esc", "F2", "1" },
  4759. // ["F2"] = new List<string> { "F1", "F3", "2" },
  4760. // ["F3"] = new List<string> { "F2", "F4", "3" },
  4761. // ["F4"] = new List<string> { "F3", "F5", "3", "4" },
  4762. // ["F5"] = new List<string> { "F4", "F6", "4", "5" },
  4763. // ["F6"] = new List<string> { "F5", "F7", "5", "6" },
  4764. // ["F7"] = new List<string> { "F6", "F8", "6", "7" },
  4765. // ["F8"] = new List<string> { "F7", "F9", "7", "8" },
  4766. // ["F9"] = new List<string> { "F8", "F10", "8", "9" },
  4767. // ["F10"] = new List<string> { "F9", "F11", "9", "0" },
  4768. // ["F11"] = new List<string> { "F10", "F12", "0", "_" },
  4769. // ["F12"] = new List<string> { "F11", "insert", "_" },
  4770. // ["insert"] = new List<string> { "F12", "delete", "~" },
  4771. // ["delete"] = new List<string> { "insert", "Power", "|" },
  4772. // ["Power"] = new List<string> { "delete", "backspace" },
  4773. // // ==============================================
  4774. // // 第二行 / 1 2 3 4 5 6 7 8 9 0 = ~ | backspace
  4775. // // ==============================================
  4776. // ["/"] = new List<string> { "Esc", "1", "tab" },
  4777. // ["1"] = new List<string> { "/", "F1", "2", "tab", "Q" },
  4778. // ["2"] = new List<string> { "1", "F2", "3", "Q", "W" },
  4779. // ["3"] = new List<string> { "2", "F3", "4", "W", "E" },
  4780. // ["4"] = new List<string> { "3", "F4", "F5", "5", "E", "R" },
  4781. // ["5"] = new List<string> { "4", "F5", "F6", "6", "R", "T" },
  4782. // ["6"] = new List<string> { "5", "F6", "F7", "7", "T", "Y" },
  4783. // ["7"] = new List<string> { "6", "F7", "F8", "8", "Y", "U" },
  4784. // ["8"] = new List<string> { "7", "F8", "F9", "9", "U", "I" },
  4785. // ["9"] = new List<string> { "8", "F9", "F10", "0", "I", "O" },
  4786. // ["0"] = new List<string> { "9", "F10", "F11", "_", "O", "P" },
  4787. // ["_"] = new List<string> { "0", "F11", "F12", "~", "P", "@" },
  4788. // ["~"] = new List<string> { "_", "insert", "|", "@", "{" },
  4789. // ["|"] = new List<string> { "~", "delete", "backspace", "{", "Enter" },
  4790. // ["backspace"] = new List<string> { "|", "Power", "Enter" },
  4791. // // ==============================================
  4792. // // 第三行 Tab Q W E R T Y U I O P @ {
  4793. // // ==============================================
  4794. // ["Tab"] = new List<string> { "/", "1", "Q", "capslock" },
  4795. // ["Q"] = new List<string> { "Tab", "1", "2", "W", "capslock", "A" },
  4796. // ["W"] = new List<string> { "Q", "2", "3", "E", "A", "S" },
  4797. // ["E"] = new List<string> { "W", "3", "4", "R", "S", "D" },
  4798. // ["R"] = new List<string> { "E", "4", "5", "T", "D", "F" },
  4799. // ["T"] = new List<string> { "R", "5", "6", "Y", "F", "G" },
  4800. // ["Y"] = new List<string> { "T", "6", "7", "U", "G", "H" },
  4801. // ["U"] = new List<string> { "Y", "7", "8", "I", "H", "J" },
  4802. // ["I"] = new List<string> { "U", "8", "9", "O", "J", "K" },
  4803. // ["O"] = new List<string> { "I", "9", "0", "P", "K", "L" },
  4804. // ["P"] = new List<string> { "O", "0", "_", "@", "L", ";" },
  4805. // ["@"] = new List<string> { "P", "_", "~", "{", ";", "*" },
  4806. // ["{"] = new List<string> { "@", "~", "|", "Enter", "*", "}" },
  4807. // // ==============================================
  4808. // // 第四行 CapsLock A S D F G H J K L ; * } Enter
  4809. // // ==============================================
  4810. // ["CapsLock"] = new List<string> { "tab", "Q", "A", "shift1" },
  4811. // ["A"] = new List<string> { "CapsLock", "Q", "W", "S", "shift1", "Z" },
  4812. // ["S"] = new List<string> { "A", "W", "E", "D", "Z", "X" },
  4813. // ["D"] = new List<string> { "S", "E", "R", "F", "X", "C" },
  4814. // ["F"] = new List<string> { "D", "R", "T", "G", "C", "V" },
  4815. // ["G"] = new List<string> { "F", "T", "Y", "H", "V", "B" },
  4816. // ["H"] = new List<string> { "G", "Y", "U", "J", "B", "N" },
  4817. // ["J"] = new List<string> { "H", "U", "I", "K", "N", "M" },
  4818. // ["K"] = new List<string> { "J", "I", "O", "L", "M", "<" },
  4819. // ["L"] = new List<string> { "K", "O", "P", ";", "<", ">" },
  4820. // [";"] = new List<string> { "L", "P", "@", "*", ">", "?" },
  4821. // ["*"] = new List<string> { ";", "@", "{", "}", "?", "\\" },
  4822. // ["}"] = new List<string> { "*", "{", "Enter", "ろ", "Shift2" },
  4823. // ["Enter"] = new List<string> { "{", "|", "backspace", "}", "Shift2" },
  4824. // // ==============================================
  4825. // // 第五行 Shift1 Z X C V B N M < > ? \ shift2
  4826. // // ==============================================
  4827. // ["shift1"] = new List<string> { "CapsLock", "A", "Z", "Ctrl1", "Fn" },
  4828. // ["Z"] = new List<string> { "shift1", "A", "S", "X", "Win" },
  4829. // ["X"] = new List<string> { "Z", "S", "D", "C", "Alt1" },
  4830. // ["C"] = new List<string> { "X", "D", "F", "V", "无变换" },
  4831. // ["V"] = new List<string> { "C", "F", "G", "B", "Space", },
  4832. // ["B"] = new List<string> { "V", "G", "H", "N", "Space" },
  4833. // ["N"] = new List<string> { "B", "H", "J", "M", "Space" },
  4834. // ["M"] = new List<string> { "N", "J", "K", "<", "Space", "变换" },
  4835. // ["<"] = new List<string> { "M", "K", "L", ">", "变换", "口" },
  4836. // [">"] = new List<string> { "<", "L", ";", "?", "口", "Ctrl2" },
  4837. // ["?"] = new List<string> { ">", ";", "*", "\\", "Ctrl2", "Left" },
  4838. // ["\\"] = new List<string> { "?", "*", "}", "Shift2", "Left", "UpDown" },
  4839. // ["Shift2"] = new List<string> { "\\", "}", "Enter", "UpDown", "Right" },
  4840. // // ==============================================
  4841. // // 第六行 Ctrl1 fn Win Alt1 无变换 Space1 Space2 变换 口 Ctrl2 Left Updown Right
  4842. // // ==============================================
  4843. // ["Ctrl1"] = new List<string> { "shift1", "Fn" },
  4844. // ["Fn"] = new List<string> { "Ctrl1", "shift1", "Win" },
  4845. // ["Win"] = new List<string> { "Fn", "Z", "Alt1" },
  4846. // ["Alt1"] = new List<string> { "Win", "X", "无变换" },
  4847. // ["无变换"] = new List<string> { "Alt1", "C", "Space" },
  4848. // ["Space"] = new List<string> { "无变换", "V", "B", "N", "M", "变换" },
  4849. // ["变换"] = new List<string> { "Space", "M", ",", "口" },
  4850. // ["口"] = new List<string> { "变换", "<", ">", "Ctrl2" },
  4851. // ["Ctrl2"] = new List<string> { "口", ">", "?", "Left" },
  4852. // ["Left"] = new List<string> { "Ctrl2", "?", "\\", "UpDown" },
  4853. // ["UpDown"] = new List<string> { "Left", "\\", "Shift2", "Right" },
  4854. // ["Right"] = new List<string> { "UpDown", "Shift2" }
  4855. //};
  4856. #endregion
  4857. return new Dictionary<string, List<string>>
  4858. {
  4859. // ==============================================
  4860. // 第一行:110 + 112~113
  4861. // ==============================================
  4862. ["110"] = new List<string> { "112", "1", },
  4863. ["112"] = new List<string> { "110", "113", "2" },
  4864. ["113"] = new List<string> { "112", "114", "3" },
  4865. ["114"] = new List<string> { "113", "115", "4" },
  4866. ["115"] = new List<string> { "114", "116", "5" },
  4867. ["116"] = new List<string> { "115", "117", "6" },
  4868. ["117"] = new List<string> { "116", "118", "7" },
  4869. ["118"] = new List<string> { "117", "119", "8" },
  4870. ["119"] = new List<string> { "118", "120", "8" },
  4871. ["120"] = new List<string> { "119", "121", "9" },
  4872. ["121"] = new List<string> { "120", "122", "10" },
  4873. ["122"] = new List<string> { "121", "123", "11" },
  4874. ["123"] = new List<string> { "122", "75", "12" },
  4875. ["75"] = new List<string> { "123", "76", "13" },
  4876. ["76"] = new List<string> { "75", "PWB", "15" },
  4877. ["PWB"] = new List<string> { "76", "15" },
  4878. // ==============================================
  4879. // 第二行:` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
  4880. // ==============================================
  4881. ["1"] = new List<string> { "110", "2", "16" },
  4882. ["2"] = new List<string> { "112", "1", "3", "16" },
  4883. ["3"] = new List<string> { "113", "2", "4", "17" },
  4884. ["4"] = new List<string> { "114", "3", "5", "19" },
  4885. ["5"] = new List<string> { "115", "4", "6", "20" },
  4886. ["6"] = new List<string> { "116", "5", "7", "21" },
  4887. ["7"] = new List<string> { "117", "6", "8", "22" },
  4888. ["8"] = new List<string> { "118", "7", "9", "23" },
  4889. ["9"] = new List<string> { "120", "8", "10", "24" },
  4890. ["10"] = new List<string> { "121", "9", "11", "25" },
  4891. ["11"] = new List<string> { "122", "10", "12", "26" },
  4892. ["12"] = new List<string> { "123", "11", "13", "27" },
  4893. ["13"] = new List<string> { "75", "12", "14", "28" },
  4894. ["14"] = new List<string> { "76", "13", "15", "28" },
  4895. ["15"] = new List<string> { "PWB", "14", "43" },
  4896. // ==============================================
  4897. // 第三行:16 17 18 19 20 21 22 23 24 25 26 27 28 29
  4898. // ==============================================
  4899. ["16"] = new List<string> { "1", "17", "30" },
  4900. ["17"] = new List<string> { "3", "16", "18", "31" },
  4901. ["18"] = new List<string> { "3", "17", "19", "32" },
  4902. ["19"] = new List<string> { "4", "18", "20", "33" },
  4903. ["20"] = new List<string> { "5", "19", "21", "34" },
  4904. ["21"] = new List<string> { "6", "20", "22", "35" },
  4905. ["22"] = new List<string> { "7", "21", "23", "36" },
  4906. ["23"] = new List<string> { "8", "22", "24", "37" },
  4907. ["24"] = new List<string> { "9", "23", "25", "38" },
  4908. ["25"] = new List<string> { "10", "24", "26", "39" },
  4909. ["26"] = new List<string> { "11", "25", "27", "40" },
  4910. ["27"] = new List<string> { "12", "26", "28", "41" },
  4911. ["28"] = new List<string> { "13", "27", "29", "43" },
  4912. ["43"] = new List<string> { "15", "28", "42", "57" },
  4913. // ==============================================
  4914. // 第四行:30 31 32 33 34 35 36 37 38 39 40 41 43
  4915. // ==============================================
  4916. ["30"] = new List<string> { "16", "31", "44" },
  4917. ["31"] = new List<string> { "17", "30", "32", "46" },
  4918. ["32"] = new List<string> { "18", "31", "33", "47" },
  4919. ["33"] = new List<string> { "19", "32", "34", "48" },
  4920. ["34"] = new List<string> { "20", "33", "35", "49" },
  4921. ["35"] = new List<string> { "21", "34", "36", "50" },
  4922. ["36"] = new List<string> { "22", "35", "37", "51" },
  4923. ["37"] = new List<string> { "23", "36", "38", "52" },
  4924. ["38"] = new List<string> { "24", "37", "39", "53" },
  4925. ["39"] = new List<string> { "25", "38", "40", "54" },
  4926. ["40"] = new List<string> { "26", "39", "41", "55" },
  4927. ["41"] = new List<string> { "27", "40", "43", "55" },
  4928. ["42"] = new List<string> { "28", "41", "57" },
  4929. // ==============================================
  4930. // 第五行:44 46 47 48 49 50 51 52 53 54 55 56 57
  4931. // ==============================================
  4932. ["44"] = new List<string> { "30", "46", "58" },
  4933. ["46"] = new List<string> { "31", "44", "47", "127" },
  4934. ["47"] = new List<string> { "32", "46", "48", "60" },
  4935. ["48"] = new List<string> { "33", "47", "49", "61_1" },
  4936. ["49"] = new List<string> { "34", "48", "50", "61_1" },
  4937. ["50"] = new List<string> { "35", "49", "51", "61_1" },
  4938. ["51"] = new List<string> { "36", "50", "52", "61_2" },
  4939. ["52"] = new List<string> { "37", "51", "53", "61_2" },
  4940. ["53"] = new List<string> { "38", "52", "54", "62" },
  4941. ["54"] = new List<string> { "39", "53", "55", "64" },
  4942. ["55"] = new List<string> { "40", "54", "56", "79" },
  4943. ["56"] = new List<string> { "41", "55", "57", "79" },
  4944. ["57"] = new List<string> { "43", "56", "89" },
  4945. // ==============================================
  4946. // 第六行:58 59 127 60 130 61_1 61_2 62 64 83_84 89
  4947. // ==============================================
  4948. ["58"] = new List<string> { "44", "59" },
  4949. ["59"] = new List<string> { "44", "58", "60" },
  4950. ["127"] = new List<string> { "46", "59", "60" },
  4951. ["60"] = new List<string> { "47", "127", "131" },
  4952. ["131"] = new List<string> { "48", "60", "61_1" },
  4953. ["61_1"] = new List<string> { "49", "131" },
  4954. ["61_2"] = new List<string> { "51", "132" },
  4955. ["132"] = new List<string> { "52", "61_2", "133" },
  4956. ["133"] = new List<string> { "53", "61_2", "64" },
  4957. ["64"] = new List<string> { "54", "133", "79" },
  4958. ["79"] = new List<string> { "55", "64", "83_84" },
  4959. ["83_84"] = new List<string> { "57", "79", "89" },
  4960. ["89"] = new List<string> { "57", "83_84" }
  4961. };
  4962. }
  4963. /// <summary>
  4964. /// 巴西键盘相邻关系
  4965. /// </summary>
  4966. private Dictionary<string, List<string>> GetBZKeyboardNeighborMap()
  4967. {
  4968. #region 之前的BZ
  4969. //return new Dictionary<string, List<string>>
  4970. //{
  4971. // // ==============================================
  4972. // // 第一行:Esc F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 Insert Delete Power
  4973. // // ==============================================
  4974. // ["ESC"] = new List<string> { "F1", "`" },
  4975. // ["F1"] = new List<string> { "ESC", "F2", "1" },
  4976. // ["F2"] = new List<string> { "F1", "F3", "2" },
  4977. // ["F3"] = new List<string> { "F2", "F4", "3" },
  4978. // ["F4"] = new List<string> { "F3", "F5", "4" },
  4979. // ["F5"] = new List<string> { "F4", "F6", "5" },
  4980. // ["F6"] = new List<string> { "F5", "F7", "6" },
  4981. // ["F7"] = new List<string> { "F6", "F8", "7" },
  4982. // ["F8"] = new List<string> { "F7", "F9", "8" },
  4983. // ["F9"] = new List<string> { "F8", "F10", "9" },
  4984. // ["F10"] = new List<string> { "F9", "F11", "0" },
  4985. // ["F11"] = new List<string> { "F10", "F12", "-" },
  4986. // ["F12"] = new List<string> { "F11", "Insert", "=" },
  4987. // ["Insert"] = new List<string> { "F12", "Backspace", "Delete" },
  4988. // ["Delete"] = new List<string> { "Insert", "Power", "Backspace" },
  4989. // ["Power"] = new List<string> { "Insert", "Delete", "Backspace" },
  4990. // // ==============================================
  4991. // // 第二行:` 1 2 3 4 5 6 7 8 9 0 _ = Backspace
  4992. // // ==============================================
  4993. // ["`"] = new List<string> { "ESC", "1", "TAB" },
  4994. // ["1"] = new List<string> { "`", "2", "F1", "Q" },
  4995. // ["2"] = new List<string> { "1", "3", "F2", "Q", "W" },
  4996. // ["3"] = new List<string> { "2", "4", "F3", "W", "E" },
  4997. // ["4"] = new List<string> { "3", "5", "F4", "E", "R" },
  4998. // ["5"] = new List<string> { "4", "6", "F5", "R", "T" },
  4999. // ["6"] = new List<string> { "5", "7", "F6", "T", "Y" },
  5000. // ["7"] = new List<string> { "6", "8", "F7", "Y", "U" },
  5001. // ["8"] = new List<string> { "7", "9", "F8", "U", "I" },
  5002. // ["9"] = new List<string> { "8", "0", "F9", "I", "O" },
  5003. // ["0"] = new List<string> { "9", "-", "F10", "O", "P" },
  5004. // ["-"] = new List<string> { "0", "=", "F11", "P", "{" },
  5005. // ["="] = new List<string> { "-", "Backspace", "F12", "{", "}" },
  5006. // ["Backspace"] = new List<string> { "=", "Insert", "}", "\\" },
  5007. // // ==============================================
  5008. // // 第三行: TAB Q W E R T Y U I O P 、 {
  5009. // // ==============================================
  5010. // ["TAB"] = new List<string> { "`", "Q", "CapsLock" },
  5011. // ["Q"] = new List<string> { "TAB", "1", "2", "W", "CapsLock" },
  5012. // ["W"] = new List<string> { "Q", "2", "3", "E", "A", "S" },
  5013. // ["E"] = new List<string> { "W", "3", "4", "R", "S", "D" },
  5014. // ["R"] = new List<string> { "E", "4", "5", "T", "D", "F" },
  5015. // ["T"] = new List<string> { "R", "5", "6", "Y", "F", "G" },
  5016. // ["Y"] = new List<string> { "T", "6", "7", "U", "G", "H" },
  5017. // ["U"] = new List<string> { "Y", "7", "8", "I", "H", "J" },
  5018. // ["I"] = new List<string> { "U", "8", "9", "O", "J", "K" },
  5019. // ["O"] = new List<string> { "I", "9", "0", "P", "K", "L" },
  5020. // ["P"] = new List<string> { "O", "0", "-", "}", "L", "Ç" },
  5021. // ["{"] = new List<string> { "P", "-", "=", "{", "Ç", "~" },
  5022. // ["}"] = new List<string> { "{", "=", "Backspace", "~", "Enter" },
  5023. // // ==============================================
  5024. // // 第四行: fixa A S D F G H J K L C5 ~ } Enter
  5025. // // ==============================================
  5026. // ["fixa"] = new List<string> { "TAB", "Q", "A", "Shift1" },
  5027. // ["A"] = new List<string> { "fixa", "Q", "W", "S", "Shift1", "Z" },
  5028. // ["S"] = new List<string> { "A", "W", "E", "D", "Z", "X" },
  5029. // ["D"] = new List<string> { "S", "E", "R", "F", "X", "C" },
  5030. // ["F"] = new List<string> { "D", "R", "T", "G", "C", "V" },
  5031. // ["G"] = new List<string> { "F", "T", "Y", "H", "V", "B" },
  5032. // ["H"] = new List<string> { "G", "Y", "U", "J", "B", "N" },
  5033. // ["J"] = new List<string> { "H", "U", "I", "K", "N", "M" },
  5034. // ["K"] = new List<string> { "J", "I", "O", "L", "M", "<" },
  5035. // ["L"] = new List<string> { "K", "O", "P", "C5", "<", ">." },
  5036. // ["C5"] = new List<string> { "L", "P", "{", "~", ">", ":" },
  5037. // ["~"] = new List<string> { "C5", "{", "}", "Enter", ":", "?" },
  5038. // ["Enter"] = new List<string> { "~", "}", "?" },
  5039. // // ==============================================
  5040. // // 第五行: Shift1 \ Z X C V B N M < > : ? Shift2
  5041. // // ==============================================
  5042. // ["Shift1"] = new List<string> { "fixa", "A", "Z", "Ctrl1" },
  5043. // ["Z"] = new List<string> { "Shift1", "A", "S", "X", "Ctrl1", "fn" },
  5044. // ["X"] = new List<string> { "Z", "S", "D", "C", "fn", "Win" },
  5045. // ["C"] = new List<string> { "X", "D", "F", "V", "Win", "Space1" },
  5046. // ["V"] = new List<string> { "C", "F", "G", "B", "Space1", "Space2" },
  5047. // ["B"] = new List<string> { "V", "G", "H", "N", "Space2", "altGr" },
  5048. // ["N"] = new List<string> { "B", "H", "J", "M", "altGr", "Ctrl2" },
  5049. // ["M"] = new List<string> { "N", "J", "K", "<", "Ctrl2", "," },
  5050. // ["<"] = new List<string> { "M", "K", "L", ">", "Shift2" },
  5051. // [">"] = new List<string> { "<", "L", "C5", ":", "Shift2" },
  5052. // [":"] = new List<string> { ">", "C5", "~", "?", "Shift2" },
  5053. // ["?"] = new List<string> { ":", "~", "Enter", "Shift2" },
  5054. // ["Shift2"] = new List<string> { "<", ">", ":", "?" },
  5055. // // ==============================================
  5056. // // 第六行: Ctrl1 Fn Win Alt1 Space1 Space2 altgr Ctr2 Left UpDown Right
  5057. // // ==============================================
  5058. // ["Ctrl1"] = new List<string> { "Shift1", "Z", "Fn" },
  5059. // ["Fn"] = new List<string> { "Ctrl1", "Z", "X", "Win" },
  5060. // ["Win"] = new List<string> { "Fn", "X", "C", "Space1" },
  5061. // ["Space1"] = new List<string> { "Win", "C", "V", "Space2" },
  5062. // ["Space2"] = new List<string> { "Space1", "V", "B", "altGr" },
  5063. // ["altGr"] = new List<string> { "Space2", "B", "N", "Ctrl2" },
  5064. // ["Ctrl2"] = new List<string> { "altGr", "N", "M", "Left" },
  5065. // ["Left"] = new List<string> { "Ctrl2", "UpDown" },
  5066. // ["UpDown"] = new List<string> { "Left", "Right" },
  5067. // ["Right"] = new List<string> { "UpDown", "Shift2" }
  5068. //};
  5069. #endregion
  5070. return new Dictionary<string, List<string>>
  5071. {
  5072. // ==============================================
  5073. // 第一行:110 + 112~113
  5074. // ==============================================
  5075. ["110"] = new List<string> { "112", "1", },
  5076. ["112"] = new List<string> { "110", "113", "2" },
  5077. ["113"] = new List<string> { "112", "114", "3" },
  5078. ["114"] = new List<string> { "113", "115", "4" },
  5079. ["115"] = new List<string> { "114", "116", "5" },
  5080. ["116"] = new List<string> { "115", "117", "6" },
  5081. ["117"] = new List<string> { "116", "118", "7" },
  5082. ["118"] = new List<string> { "117", "119", "8" },
  5083. ["119"] = new List<string> { "118", "120", "8" },
  5084. ["120"] = new List<string> { "119", "121", "9" },
  5085. ["121"] = new List<string> { "120", "122", "10" },
  5086. ["122"] = new List<string> { "121", "123", "11" },
  5087. ["123"] = new List<string> { "122", "75", "12" },
  5088. ["75"] = new List<string> { "123", "76", "13" },
  5089. ["76"] = new List<string> { "75", "PWB", "15" },
  5090. ["PWB"] = new List<string> { "76", "15" },
  5091. // ==============================================
  5092. // 第二行:` 1 2 3 4 5 6 7 8 9 10 11 12 13 15
  5093. // ==============================================
  5094. ["1"] = new List<string> { "110", "2", "16" },
  5095. ["2"] = new List<string> { "112", "1", "3", "16" },
  5096. ["3"] = new List<string> { "113", "2", "4", "17" },
  5097. ["4"] = new List<string> { "114", "3", "5", "19" },
  5098. ["5"] = new List<string> { "115", "4", "6", "20" },
  5099. ["6"] = new List<string> { "116", "5", "7", "21" },
  5100. ["7"] = new List<string> { "117", "6", "8", "22" },
  5101. ["8"] = new List<string> { "118", "7", "9", "23" },
  5102. ["9"] = new List<string> { "120", "8", "10", "24" },
  5103. ["10"] = new List<string> { "121", "9", "11", "25" },
  5104. ["11"] = new List<string> { "122", "10", "12", "26" },
  5105. ["12"] = new List<string> { "123", "11", "13", "27" },
  5106. ["13"] = new List<string> { "75", "12", "15", "28" },
  5107. ["15"] = new List<string> { "76", "13", "43" },
  5108. // ==============================================
  5109. // 第三行:16 17 18 19 20 21 22 23 24 25 26 27 28 29
  5110. // ==============================================
  5111. ["16"] = new List<string> { "1", "17", "30" },
  5112. ["17"] = new List<string> { "3", "16", "18", "31" },
  5113. ["18"] = new List<string> { "3", "17", "19", "32" },
  5114. ["19"] = new List<string> { "4", "18", "20", "33" },
  5115. ["20"] = new List<string> { "5", "19", "21", "34" },
  5116. ["21"] = new List<string> { "6", "20", "22", "35" },
  5117. ["22"] = new List<string> { "7", "21", "23", "36" },
  5118. ["23"] = new List<string> { "8", "22", "24", "37" },
  5119. ["24"] = new List<string> { "9", "23", "25", "38" },
  5120. ["25"] = new List<string> { "10", "24", "26", "39" },
  5121. ["26"] = new List<string> { "11", "25", "27", "40" },
  5122. ["27"] = new List<string> { "12", "26", "28", "41" },
  5123. ["28"] = new List<string> { "13", "27", "43", "42" },
  5124. ["43"] = new List<string> { "15", "28", "57" },
  5125. // ==============================================
  5126. // 第四行:30 31 32 33 34 35 36 37 38 39 40 41 43
  5127. // ==============================================
  5128. ["30"] = new List<string> { "16", "31", "44" },
  5129. ["31"] = new List<string> { "17", "30", "32", "46" },
  5130. ["32"] = new List<string> { "18", "31", "33", "47" },
  5131. ["33"] = new List<string> { "19", "32", "34", "48" },
  5132. ["34"] = new List<string> { "20", "33", "35", "49" },
  5133. ["35"] = new List<string> { "21", "34", "36", "50" },
  5134. ["36"] = new List<string> { "22", "35", "37", "51" },
  5135. ["37"] = new List<string> { "23", "36", "38", "52" },
  5136. ["38"] = new List<string> { "24", "37", "39", "53" },
  5137. ["39"] = new List<string> { "25", "38", "40", "54" },
  5138. ["40"] = new List<string> { "26", "39", "41", "55" },
  5139. ["41"] = new List<string> { "27", "40", "42", "55" },
  5140. ["42"] = new List<string> { "29", "41", "57" },
  5141. // ==============================================
  5142. // 第五行:44 46 47 48 49 50 51 52 53 54 55 57
  5143. // ==============================================
  5144. ["44"] = new List<string> { "30", "45", "58" },
  5145. ["45"] = new List<string> { "30", "44", "46", "59" },
  5146. ["46"] = new List<string> { "31", "44", "47", "127" },
  5147. ["47"] = new List<string> { "32", "46", "48", "60" },
  5148. ["48"] = new List<string> { "33", "47", "49", "61_1" },
  5149. ["49"] = new List<string> { "34", "48", "50", "61_1" },
  5150. ["50"] = new List<string> { "35", "49", "51", "61_1" },
  5151. ["51"] = new List<string> { "36", "50", "52", "61_2" },
  5152. ["52"] = new List<string> { "37", "51", "53", "61_2" },
  5153. ["53"] = new List<string> { "38", "52", "54", "62" },
  5154. ["54"] = new List<string> { "39", "53", "55", "64" },
  5155. ["55"] = new List<string> { "40", "54", "56", "79" },
  5156. ["56"] = new List<string> { "41", "55", "57", "79" },
  5157. ["57"] = new List<string> { "43", "55", "89" },
  5158. // ==============================================
  5159. // 第六行:58 59 127 60 61_1 61_2 62 64 83_84 89
  5160. // ==============================================
  5161. ["58"] = new List<string> { "44", "59" },
  5162. ["59"] = new List<string> { "44", "58", "60" },
  5163. ["127"] = new List<string> { "46", "59", "60" },
  5164. ["60"] = new List<string> { "47", "127", "61_1" },
  5165. ["61_1"] = new List<string> { "49", "60" },
  5166. ["61_2"] = new List<string> { "51", "62" },
  5167. // ["RightFn"] = new List<string> { "RightAlt", "RightCtrl" },
  5168. ["62"] = new List<string> { "53", "61_2", "64" },
  5169. ["64"] = new List<string> { "54", "62", "79" },
  5170. ["79"] = new List<string> { "55", "64", "83_84" },
  5171. ["83_84"] = new List<string> { "57", "79", "89" },
  5172. ["89"] = new List<string> { "57", "83_84" }
  5173. };
  5174. }
  5175. private Dictionary<string, double> GetAdjacentDiffDict(ConcurrentDictionary<string, double> keyData, string name)
  5176. {
  5177. var currentProduct = _productService.GetCurrentProduct();
  5178. Dictionary<string, double> diffDict = new Dictionary<string, double>();
  5179. var neighborMap = GetUSKeyboardNeighborMap();
  5180. if (name.Contains("US"))
  5181. {
  5182. neighborMap = GetUSKeyboardNeighborMap();
  5183. }
  5184. else if (name.Contains("UK"))
  5185. {
  5186. neighborMap = GetUKKeyboardNeighborMap();
  5187. }
  5188. else if (name.Contains("JP"))
  5189. {
  5190. neighborMap = GetJPKeyboardNeighborMap();
  5191. }
  5192. else if (name.Contains("BZ"))
  5193. {
  5194. neighborMap = GetBZKeyboardNeighborMap();
  5195. }
  5196. else
  5197. {
  5198. SendTaskMessage("未查找到当前产品名称的键盘相邻关系", MessageLevel.Error);
  5199. }
  5200. foreach (var kvp in keyData)
  5201. {
  5202. string key1 = kvp.Key;
  5203. double val1 = kvp.Value;
  5204. if (!neighborMap.TryGetValue(key1, out var neighbors)) continue;
  5205. foreach (string key2 in neighbors)
  5206. {
  5207. if (!keyData.TryGetValue(key2, out double val2)) continue;
  5208. // 去重核心:保证 A-S 和 S-A 只存一次
  5209. string pairKey = string.Compare(key1, key2) < 0 ? $"_{key1}_{key2}" : $"_{key2}_{key1}";
  5210. if (diffDict.ContainsKey(pairKey)) continue; // 跳过已存的
  5211. double diff = Math.Abs(val1 - val2);
  5212. diffDict.Add(pairKey, diff);
  5213. }
  5214. }
  5215. return diffDict;
  5216. }
  5217. #endregion
  5218. #region vm启动检测
  5219. /// <summary>
  5220. /// 杀死所有VM有关进程
  5221. /// </summary>
  5222. public void KillVMProcess()
  5223. {
  5224. KillProcess("VisionMasterServerApp");
  5225. KillProcess("VisionMaster");
  5226. KillProcess("VmModuleProxy.exe");
  5227. KillProcess("vServerApp.exe");
  5228. }
  5229. /// <summary>
  5230. /// 杀死指定进程名的进程
  5231. /// </summary>
  5232. /// <param name="strKillName"></param>
  5233. public void KillProcess(string strKillName)
  5234. {
  5235. foreach (System.Diagnostics.Process p in System.Diagnostics.Process.GetProcesses())
  5236. {
  5237. if (p.ProcessName.Contains(strKillName))
  5238. {
  5239. try
  5240. {
  5241. p.Kill();
  5242. p.WaitForExit();
  5243. }
  5244. catch (Exception ex)
  5245. {
  5246. LogHelper.WriteLogError($"杀死进程:{strKillName}时失败!", ex);
  5247. }
  5248. }
  5249. }
  5250. }
  5251. #endregion
  5252. #region 保存CSV
  5253. public bool WriteProductLogKB(IEnumerable<DataFormCtq> lockResults, string rfid)
  5254. {
  5255. try
  5256. {
  5257. DateTime dt = DateTime.Now;
  5258. if (rfid == null || rfid.Count() == 0)
  5259. {
  5260. rfid = dt.ToString("MM-dd-mm");
  5261. }
  5262. if (lockResults.Count() == 0 || lockResults == null)
  5263. {
  5264. SendTaskMessage("保存KB数据为空", MessageLevel.Error);
  5265. return false;
  5266. }
  5267. string path = $"D:\\Data\\JMS数据\\{dt.ToString("yyyy-MM")}\\{dt.ToString("yyyy-MM-dd")}\\KB_{rfid}.csv";
  5268. StringBuilder sb = new StringBuilder();
  5269. sb.Append($"PD_ATTR_01,CTQ_NAME,CTQ_VALUE,");
  5270. sb.AppendLine();
  5271. foreach (var item in lockResults)
  5272. {
  5273. try
  5274. {
  5275. //!item.CTQ_NAME.Contains("Left")|| !item.CTQ_NAME.Contains("Right")||!item.CTQ_NAME.Contains("Updown")|| !item.CTQ_NAME.Contains("Down")
  5276. if (item.CTQ_NAME.Contains("Left") || item.CTQ_NAME.Contains("Down") || item.CTQ_NAME.Contains("Right") || item.CTQ_NAME.Contains("Updown"))
  5277. {
  5278. }
  5279. else
  5280. {
  5281. sb.Append($"{item.PD_ATTR_01},{item.CTQ_NAME},{item.CTQ_VALUE},");
  5282. sb.AppendLine();
  5283. }
  5284. }
  5285. catch (Exception)
  5286. {
  5287. sb.Append($",,,,,,,,,,,,,,");
  5288. return false;
  5289. }
  5290. }
  5291. if (!Directory.Exists(Path.GetDirectoryName(path))) //判断文件夹是否
  5292. {
  5293. Directory.CreateDirectory(Path.GetDirectoryName(path)); //创建文件夹
  5294. }
  5295. if (File.Exists(path))
  5296. {
  5297. // 使用 StreamWriter 以追加模式打开文件
  5298. StreamWriter sw = new StreamWriter(path, true, Encoding.UTF8);
  5299. sw.WriteLine(sb.ToString().TrimEnd(','));
  5300. //sw.WriteLine(sb1.ToString().TrimEnd(','));
  5301. sw.Close();
  5302. sw.Dispose();
  5303. }
  5304. else
  5305. {
  5306. StreamWriter sw = new StreamWriter(path, true, Encoding.UTF8);
  5307. sw.WriteLine(sb.ToString().TrimEnd(','));
  5308. sw.Close();
  5309. sw.Dispose();
  5310. }
  5311. return true;
  5312. }
  5313. catch (Exception ex)
  5314. {
  5315. LogHelper.WriteLogError("写入产品记录时出错!", ex);
  5316. return false;
  5317. }
  5318. }
  5319. public bool WriteProductLogTP(IEnumerable<DataFormCtq> lockResults, string rfid)
  5320. {
  5321. try
  5322. {
  5323. DateTime dt = DateTime.Now;
  5324. if (rfid == null || rfid.Count() == 0)
  5325. {
  5326. rfid = dt.ToString("MM-dd-mm");
  5327. }
  5328. if (lockResults.Count() == 0 || lockResults == null)
  5329. {
  5330. SendTaskMessage("保存KB数据为空", MessageLevel.Error);
  5331. return false;
  5332. }
  5333. string path = $"D:\\Data\\JMS数据\\{dt.ToString("yyyy-MM")}\\{dt.ToString("yyyy-MM-dd")}\\TP_{rfid}.csv";
  5334. StringBuilder sb = new StringBuilder();
  5335. sb.Append($"PD_ATTR_01,CTQ_NAME,CTQ_VALUE,");
  5336. sb.AppendLine();
  5337. foreach (var item in lockResults)
  5338. {
  5339. try
  5340. {
  5341. if (item.CTQ_NAME.Contains("Left") || item.CTQ_NAME.Contains("Down") || item.CTQ_NAME.Contains("Right") || item.CTQ_NAME.Contains("Updown"))
  5342. {
  5343. sb.Append($"{item.PD_ATTR_01},{item.CTQ_NAME},{item.CTQ_VALUE},");
  5344. sb.AppendLine();
  5345. }
  5346. }
  5347. catch (Exception)
  5348. {
  5349. sb.Append($",,,,,,,,,,,,,,");
  5350. return false;
  5351. }
  5352. }
  5353. if (!Directory.Exists(Path.GetDirectoryName(path))) //判断文件夹是否
  5354. {
  5355. Directory.CreateDirectory(Path.GetDirectoryName(path)); //创建文件夹
  5356. }
  5357. if (File.Exists(path))
  5358. {
  5359. // 使用 StreamWriter 以追加模式打开文件
  5360. StreamWriter sw = new StreamWriter(path, true, Encoding.UTF8);
  5361. sw.WriteLine(sb.ToString().TrimEnd(','));
  5362. //sw.WriteLine(sb1.ToString().TrimEnd(','));
  5363. sw.Close();
  5364. sw.Dispose();
  5365. }
  5366. else
  5367. {
  5368. StreamWriter sw = new StreamWriter(path, true, Encoding.UTF8);
  5369. sw.WriteLine(sb.ToString().TrimEnd(','));
  5370. sw.Close();
  5371. sw.Dispose();
  5372. }
  5373. return true;
  5374. }
  5375. catch (Exception ex)
  5376. {
  5377. LogHelper.WriteLogError("写入产品记录时出错!", ex);
  5378. return false;
  5379. }
  5380. }
  5381. /// <summary>
  5382. /// 记录工位的结果,其他工位要存储的数据项按照键值对集合的形式传入,键为数据项名称,值为数据项的值
  5383. /// </summary>
  5384. /// <param name="stationIndex"></param>
  5385. /// <param name="dfcs"></param>
  5386. /// <param name="productMainSN"></param>
  5387. /// <param name="ct"></param>
  5388. /// <param name="timestamp"></param>
  5389. /// <param name="savePath"></param>
  5390. /// <param name="isFirstEnter"></param>
  5391. /// <returns></returns>
  5392. private bool RecordStationResult(int stationIndex, IEnumerable<DataFormCtq> dfcs, string productMainSN, double ct, DateTime timestamp, string savePath, out string actualPath, bool isFirstEnter = true)
  5393. {
  5394. actualPath = null;
  5395. try
  5396. {
  5397. //获取当前工位的配置
  5398. var stationConfig = _configService.GetDeviceInfo(0);
  5399. if (stationConfig == null) return false;
  5400. //如果保存路径为空,则不保存
  5401. if (string.IsNullOrEmpty(savePath)) return false;
  5402. string fullPath = savePath;
  5403. //如果保存路径是一个文件路径,则直接保存,否则按照工位和日期进行保存
  5404. if (File.Exists(savePath) || Path.HasExtension(savePath))
  5405. {
  5406. fullPath = savePath;
  5407. //如果路径不存在,则创建
  5408. // 创建目录
  5409. string directory = Path.GetDirectoryName(fullPath);
  5410. if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
  5411. {
  5412. Directory.CreateDirectory(directory);
  5413. }
  5414. }
  5415. else
  5416. {
  5417. //结果保存至CSV文件,文件名格式:savePath\yyyy-MM\工位编号_工位名称_yyyy-MM-dd.csv
  5418. string datePath = timestamp.ToString("yyyy-MM") + "\\";
  5419. string dirPath = Path.Combine(savePath, datePath);
  5420. if (!Directory.Exists(dirPath)) Directory.CreateDirectory(dirPath);
  5421. string fileName = $"{stationIndex}_{stationConfig.DeviceName}_{timestamp.ToString("yyyy-MM-dd")}.csv";
  5422. fullPath = Path.Combine(dirPath, fileName);
  5423. }
  5424. // ========== 新增:检查文件行数,如果达到上限则自动分片 ==========
  5425. fullPath = GetAvailableFilePath(fullPath);
  5426. // ============================================================
  5427. StringBuilder sb = new StringBuilder();
  5428. if (!File.Exists(fullPath))
  5429. {
  5430. sb.Append("PPID,PROCESS_NAME,PROCESS_START_TIME,CTQ_NAME,CTQ_VALUE,CTQ_LSL,CTQ_USL,PROCESS_END_TIME,SUPPLIER_NAME,COMMODITY_TYPE,REVISION,WO#,MFG_LOT#," +
  5431. "MFG_ASSY_LINE,PROCESS_OUTCOME,PROCESS_MACHINE_ID,CTQ_UNIT_OF_MEASURE,ERROR_MESSAGE,PD_ATTR_01,PD_ATTR_02,PD_ATTR_03,PD_ATTR_04,PD_ATTR_05,PD_ATTR_06");
  5432. sb.AppendLine();
  5433. }
  5434. if (dfcs == null || dfcs.Count() == 0)
  5435. {
  5436. return false;
  5437. }
  5438. foreach (var dfc in dfcs)
  5439. {
  5440. sb.Append($"{dfc.PPID},{dfc.PROCESS_NAME},{dfc.PROCESS_START_TIME},{dfc.CTQ_NAME},{dfc.CTQ_VALUE},{dfc.CTQ_LSL},{dfc.CTQ_USL},{dfc.PROCESS_END_TIME},{dfc.SUPPLIER_NAME},{dfc.COMMODITY_TYPE},{dfc.REVISION},{dfc.WO},{dfc.MFG_LOT},{dfc.MFG_ASSY_LINE},{dfc.PROCESS_OUTCOME},{dfc.PROCESS_MACHINE_ID},{dfc.CTQ_UNIT_OF_MEASURE},{dfc.ERROR_MESSAGE},{dfc.PD_ATTR_01},{dfc.PD_ATTR_02},{dfc.PD_ATTR_03},{dfc.PD_ATTR_04},{dfc.PD_ATTR_05},{dfc.PD_ATTR_06}");
  5441. sb.AppendLine();
  5442. }
  5443. // 使用 StreamWriter 以追加模式写入,使用 using 确保异常时句柄不泄漏
  5444. try
  5445. {
  5446. using (StreamWriter sw = new StreamWriter(fullPath, true, Encoding.UTF8))
  5447. {
  5448. sw.Write(sb.ToString());
  5449. }
  5450. actualPath = fullPath;
  5451. return true;
  5452. }
  5453. catch (IOException ioEx) when (ioEx.Message.Contains("另一进程") || ioEx.Message.Contains("being used"))
  5454. {
  5455. // 主文件被占用,生成备份文件写入
  5456. string mainDir = Path.GetDirectoryName(fullPath);
  5457. if (string.IsNullOrEmpty(mainDir))
  5458. mainDir = savePath;
  5459. string backupDir = Path.Combine(mainDir, "Backup");
  5460. if (!Directory.Exists(backupDir))
  5461. Directory.CreateDirectory(backupDir);
  5462. string backupFileName = $"{stationIndex}_{stationConfig.DeviceName}_{DateTime.Now:yyyy-MM-dd_HHmmssfff}.csv";
  5463. string backupPath = Path.Combine(backupDir, backupFileName);
  5464. using (StreamWriter sw = new StreamWriter(backupPath, false, Encoding.UTF8))
  5465. {
  5466. sw.Write(sb.ToString());
  5467. }
  5468. actualPath = backupPath;
  5469. SendTaskMessage($"主CSV文件被占用,已写入备份文件: {backupPath}", MessageLevel.Alarm);
  5470. LogHelper.WriteLogInfo($"CSV主文件被占用,已写备份: 主={fullPath}, 备份={backupPath}");
  5471. return true;
  5472. }
  5473. }
  5474. catch (Exception ex)
  5475. {
  5476. LogHelper.WriteLogError("记录其他工位结果时出错!", ex);
  5477. return false;
  5478. }
  5479. }
  5480. /// <summary>
  5481. /// 记录工位的NG结果
  5482. /// </summary>
  5483. /// <param name="dfcs">NG数据</param>
  5484. /// <param name="timestamp">时间</param>
  5485. /// <returns></returns>
  5486. private bool RecordStationNGResult(IEnumerable<DataFormCtq> dfcs, DateTime timestamp)
  5487. {
  5488. try
  5489. {
  5490. string datePath = timestamp.ToString("yyyy-MM") + "\\";
  5491. string dirPath = Path.Combine(@"D:\NG", datePath);
  5492. if (!Directory.Exists(dirPath)) Directory.CreateDirectory(dirPath);
  5493. string fileName = $"NG_{timestamp.ToString("yyyy-MM-dd")}.csv";
  5494. string fullPath = Path.Combine(dirPath, fileName);
  5495. // ============================================================
  5496. StringBuilder sb = new StringBuilder();
  5497. if (!File.Exists(fullPath))
  5498. {
  5499. sb.Append("PD_ATTR_01,ERROR_MESSAGE,PROCESS_START_TIME,PROCESS_END_TIME");
  5500. sb.AppendLine();
  5501. }
  5502. if (dfcs == null || dfcs.Count() == 0)
  5503. {
  5504. return false;
  5505. }
  5506. foreach (var dfc in dfcs)
  5507. {
  5508. sb.Append($"{dfc.PD_ATTR_01},{dfc.ERROR_MESSAGE},{dfc.PROCESS_START_TIME},{dfc.PROCESS_END_TIME}");
  5509. sb.AppendLine();
  5510. }
  5511. // 使用 StreamWriter 以追加模式打开文件
  5512. StreamWriter sw = new StreamWriter(fullPath, true, Encoding.UTF8);
  5513. sw.Write(sb.ToString());
  5514. sw.Close();
  5515. sw.Dispose();
  5516. return true;
  5517. }
  5518. catch (Exception ex)
  5519. {
  5520. LogHelper.WriteLogError("记录其他工位结果时出错!", ex);
  5521. return false;
  5522. }
  5523. }
  5524. /// <summary>
  5525. /// Excel 最大行数限制(Excel 2007+ 为 1048576 行,这里设为 1000000 留有余量)
  5526. /// </summary>
  5527. private const int MaxExcelRows = 1000000;
  5528. /// <summary>
  5529. /// 获取可用的文件路径,如果当前文件行数达到上限,则自动生成新文件
  5530. /// </summary>
  5531. private string GetAvailableFilePath(string originalPath)
  5532. {
  5533. // 如果文件不存在,直接返回原路径
  5534. if (!File.Exists(originalPath))
  5535. {
  5536. return originalPath;
  5537. }
  5538. // 获取当前文件的行数(包含表头)
  5539. int currentRowCount = GetFileRowCount(originalPath);
  5540. // 如果当前行数未达到上限,直接返回原路径
  5541. if (currentRowCount < MaxExcelRows)
  5542. {
  5543. return originalPath;
  5544. }
  5545. // 文件已达上限,生成新文件路径
  5546. string directory = Path.GetDirectoryName(originalPath);
  5547. string fileName = Path.GetFileNameWithoutExtension(originalPath);
  5548. string extension = Path.GetExtension(originalPath);
  5549. // 查找可用的序号
  5550. int fileIndex = 1;
  5551. string newPath;
  5552. do
  5553. {
  5554. string newFileName = $"{fileName}_{fileIndex:D4}{extension}";
  5555. newPath = Path.Combine(directory, newFileName);
  5556. fileIndex++;
  5557. // 如果新文件存在,检查它的行数是否也达到上限
  5558. if (File.Exists(newPath))
  5559. {
  5560. int newFileRowCount = GetFileRowCount(newPath);
  5561. if (newFileRowCount < MaxExcelRows)
  5562. {
  5563. // 这个文件可用,直接返回
  5564. return newPath;
  5565. }
  5566. // 否则继续找下一个
  5567. }
  5568. else
  5569. {
  5570. // 新文件不存在,可用
  5571. return newPath;
  5572. }
  5573. } while (true);
  5574. }
  5575. /// <summary>
  5576. /// 获取 CSV 文件的行数(快速方法,只读取第一行和总行数)
  5577. /// </summary>
  5578. private int GetFileRowCount(string filePath)
  5579. {
  5580. try
  5581. {
  5582. // 使用 StreamReader 快速获取行数
  5583. using (var reader = new StreamReader(filePath, Encoding.UTF8))
  5584. {
  5585. int lineCount = 0;
  5586. while (reader.ReadLine() != null)
  5587. {
  5588. lineCount++;
  5589. }
  5590. return lineCount;
  5591. }
  5592. }
  5593. catch
  5594. {
  5595. // 如果读取失败,假设文件为0行(安全处理)
  5596. return 0;
  5597. }
  5598. }
  5599. #endregion
  5600. private async void DoYieldTime(object state)
  5601. {
  5602. try
  5603. {
  5604. //获取当前产品
  5605. var currentproduct = _productService.GetCurrentProduct();
  5606. CurrentProduct = _productService.GetCurrentProduct();
  5607. if (currentproduct == null) return;
  5608. TotalQuantity = await _systemDatabaseService.GetOverallProductionAsync(currentproduct.Name);
  5609. TotalQuantityToday = 0;
  5610. CurrentUPH = 0;
  5611. //NgNumber = 0;
  5612. //Yield = 0;
  5613. ObservableCollection<ProductModel> ProductList = new ObservableCollection<ProductModel>(_productService.GetAllProducts());
  5614. foreach (var product in ProductList)
  5615. {
  5616. //TotalQuantity += await _systemDatabaseService.GetOverallProductionAsync(product.Name);
  5617. TotalQuantityToday += await _systemDatabaseService.GetTodayProductionAsync(product.Name);
  5618. CurrentUPH += await _systemDatabaseService.GetLastHourProductionAsync(product.Name);
  5619. //NgNumber += await _systemDatabaseService.GetNGProductionAsync(product.Name);
  5620. }
  5621. }
  5622. catch (Exception)
  5623. {
  5624. }
  5625. }
  5626. // 用于等待“指定相机的下一张图到达”
  5627. private readonly object _imageSyncLock = new object();
  5628. private readonly Dictionary<Guid, TaskCompletionSource<ICogImage>> _nextImageTcsByCamera =
  5629. new Dictionary<Guid, TaskCompletionSource<ICogImage>>();
  5630. private Task<ICogImage> PrepareNextImageWait(Guid cameraId)
  5631. {
  5632. lock (_imageSyncLock)
  5633. {
  5634. var tcs = new TaskCompletionSource<ICogImage>(TaskCreationOptions.RunContinuationsAsynchronously);
  5635. _nextImageTcsByCamera[cameraId] = tcs;
  5636. return tcs.Task;
  5637. }
  5638. }
  5639. public async Task SignalImageArrived(Guid cameraId, ICogImage image)
  5640. {
  5641. await Task.Delay(500);
  5642. TaskCompletionSource<ICogImage> tcs = null;
  5643. lock (_imageSyncLock)
  5644. {
  5645. _nextImageTcsByCamera.TryGetValue(cameraId, out tcs);
  5646. }
  5647. tcs?.TrySetResult(image);
  5648. }
  5649. public async Task<ICogImage> WaitNextImageAsync(Guid cameraId, int timeoutMs, CancellationToken token)
  5650. {
  5651. var waitTask = PrepareNextImageWait(cameraId);
  5652. var completed = await Task.WhenAny(waitTask, Task.Delay(timeoutMs, token)).ConfigureAwait(false);
  5653. if (completed != waitTask) return null;
  5654. return await waitTask.ConfigureAwait(false);
  5655. }
  5656. private Guid GetDefaultScannerId()
  5657. {
  5658. if (_defaultScannerId != Guid.Empty) return _defaultScannerId;
  5659. var scannerInfo = _configService.GetAllScanners()
  5660. .OrderBy(s => s.ScannerNo)
  5661. .FirstOrDefault();
  5662. _defaultScannerId = scannerInfo == null ? Guid.Empty : scannerInfo.Id;
  5663. return _defaultScannerId;
  5664. }
  5665. private async Task Scan_DataReceived(ISerialPortClient client, ReceivedDataEventArgs e)
  5666. {
  5667. try
  5668. {
  5669. // 串口名
  5670. string portName = client.MainSerialPort.PortName;
  5671. // 注意:DataReceived 可能一次收到多段/包含回车换行
  5672. string data = e.ByteBlock.Span.ToString(Encoding.ASCII);
  5673. await Console.Out.WriteLineAsync(data);
  5674. // 取第一段(到 \r 之前),并去掉首尾空白
  5675. string response = data.Split('\r')[0].Trim();
  5676. // 过滤:空数据不要当成一次有效扫码
  5677. if (string.IsNullOrWhiteSpace(response))
  5678. return;
  5679. SendTaskMessage($"扫码机:{portName} Receive:{response}", MessageLevel.Info);
  5680. // 写入结果
  5681. ScanValue = response;
  5682. // 通知等待方继续执行(PLC 逻辑里 Wait 的地方)
  5683. _scanDoneEvent.Set();
  5684. }
  5685. catch (Exception ex)
  5686. {
  5687. LogHelper.WriteLogError("扫码枪接收信息时出错!", ex);
  5688. SendTaskMessage(Lang.扫码枪接收信息时出错 + ex.Message, MessageLevel.Error);
  5689. }
  5690. }
  5691. /// <summary>
  5692. /// 2D相机先采集图像
  5693. /// </summary>
  5694. /// <param name="procedureId"></param>
  5695. /// <returns></returns>
  5696. private async Task<(bool IsSucceed, ICogImage[] imges, string Message, int pointIndex, Guid procedureId)> GrabImageEx(int pointIndex, Guid procedureId, bool Is3dPhoto, ProductModel currentProduct, SystemConfiguration sysConfig)
  5697. {
  5698. // 获取当前产品
  5699. //var currentProduct = _productService.GetCurrentProduct();
  5700. if (currentProduct == null)
  5701. {
  5702. return (false, null, "当前产品为空,未加载产品!", pointIndex, procedureId);
  5703. }
  5704. var cameraProcedures = currentProduct.CameraProcedures;
  5705. if (cameraProcedures == null || cameraProcedures.Count == 0)
  5706. {
  5707. SendTaskMessage($"当前产品未配置 CameraProcedures,无法执行视觉流程", MessageLevel.Alarm);
  5708. return (false, null, $"当前产品未配置 CameraProcedures,无法执行视觉流程", pointIndex, procedureId);
  5709. }
  5710. try
  5711. {
  5712. ProcedureModel selectedProcedure = null;
  5713. try
  5714. {
  5715. foreach (var cp in cameraProcedures)
  5716. {
  5717. if (cp?.ProcedureModels == null) continue;
  5718. selectedProcedure = cp.ProcedureModels.FirstOrDefault(pm => pm.Id == procedureId);
  5719. if (selectedProcedure != null) break;
  5720. }
  5721. }
  5722. catch (Exception ex)
  5723. {
  5724. LogHelper.WriteLogError("查找 AOI 点位对应视觉流程时出错", ex);
  5725. }
  5726. if (selectedProcedure == null)
  5727. {
  5728. SendTaskMessage($"未找到 AOI 点位对应的视觉流程,Point#{pointIndex} ProcedureId={pointIndex}", MessageLevel.Alarm);
  5729. return (false, null, $"未找到 AOI 点位对应的视觉流程,Point#{pointIndex} ProcedureId={procedureId}", pointIndex, procedureId);
  5730. }
  5731. SendTaskMessage($"开始执行 AOI 流程 (Point#{pointIndex}) 流程Id={pointIndex}", MessageLevel.Debug);
  5732. try
  5733. {
  5734. //var sysConfig = _configService.GetSystemConfiguration();
  5735. if (selectedProcedure.Id == currentProduct.FixedDownCameraProcedureId && sysConfig.TurnOnAllLightUse == true)
  5736. {
  5737. await _remoteCommandService.SetLightBeforePhoto(selectedProcedure);
  5738. }
  5739. //1. 执行拍照
  5740. var res = await _remoteCommandService.ExecuteGrabImageAsync(selectedProcedure, Is3dPhoto, sysConfig);
  5741. return (res.IsSucceed, res.Image, res.Msg, pointIndex, procedureId);
  5742. }
  5743. catch (Exception ex)
  5744. {
  5745. LogHelper.WriteLogError("执行 AOI 视觉图像采集时出错", ex);
  5746. SendTaskMessage($"执行 AOI 视觉图像采集时出错: {ex.Message}", MessageLevel.Alarm);
  5747. }
  5748. return (false, null, $"图像采集失败", pointIndex, procedureId);
  5749. }
  5750. catch (Exception ex)
  5751. {
  5752. LogHelper.WriteLogError("处理固定相机检测拍照时出错", ex);
  5753. return (false, null, $"处理固定相机检测拍照时出错", pointIndex, procedureId);
  5754. }
  5755. }
  5756. #region 压缩图片文件夹
  5757. /// <summary>
  5758. /// 压缩文件
  5759. /// </summary>
  5760. /// <param name="sourcePath">原路径</param>
  5761. /// <param name="zipname">压缩后文件的名称</param>
  5762. /// <param name="station">mes中的station</param>
  5763. /// <param name="fixid">mes中的fixtureID</param>
  5764. public async void CompressionImage(string sourcePath, string zipname, string station, string fixid)
  5765. {
  5766. string zipPath = "";
  5767. try
  5768. {
  5769. SendTaskMessage($"开始压缩文件", MessageLevel.Info);
  5770. await Task.Run(() =>
  5771. {
  5772. zipPath = $"Z:\\{station}\\{fixid}\\{DateTime.Now.ToString("yyyyMMdd")}\\{zipname}.zip";//生成的zip文件路径
  5773. string path = $"Z:\\{station}\\{fixid}\\{DateTime.Now.ToString("yyyyMMdd")}";
  5774. if (!Directory.Exists(path))
  5775. {
  5776. Directory.CreateDirectory(path);
  5777. }
  5778. ZipFile.CreateFromDirectory(sourcePath, zipPath);
  5779. });
  5780. }
  5781. catch (Exception ex)
  5782. {
  5783. LogHelper.WriteLogError($"压缩文件时出错", ex);
  5784. }
  5785. }
  5786. public async void CompressionSingleCsv(string csvFilePath, string zipname, string station, string fixid)
  5787. {
  5788. string zipPath = "";
  5789. try
  5790. {
  5791. SendTaskMessage("开始压缩CSV文件", MessageLevel.Info);
  5792. await Task.Run(() =>
  5793. {
  5794. if (!File.Exists(csvFilePath))
  5795. {
  5796. LogHelper.WriteLogMes($"CSV文件不存在,不压缩:{csvFilePath}");
  5797. return;
  5798. }
  5799. zipPath = $"Z:\\{station}\\{fixid}\\{DateTime.Now.ToString("yyyyMMdd")}\\{zipname}.zip";
  5800. string path = $"Z:\\{station}\\{fixid}\\{DateTime.Now.ToString("yyyyMMdd")}";
  5801. if (!Directory.Exists(path))
  5802. {
  5803. Directory.CreateDirectory(path);
  5804. }
  5805. using (FileStream fs = new FileStream(zipPath, FileMode.Create))
  5806. {
  5807. using (ZipArchive archive = new ZipArchive(fs, ZipArchiveMode.Create))
  5808. {
  5809. archive.CreateEntryFromFile(csvFilePath, Path.GetFileName(csvFilePath));
  5810. }
  5811. }
  5812. });
  5813. SendTaskMessage("CSV文件压缩完成", MessageLevel.Debug);
  5814. }
  5815. catch (Exception ex)
  5816. {
  5817. LogHelper.WriteLogError("压缩CSV文件失败", ex);
  5818. }
  5819. }
  5820. #endregion
  5821. //#region 读取写入plc速度
  5822. //// 速度数据模型
  5823. //[Serializable]
  5824. //public class SpeedData
  5825. //{
  5826. // public string SpeedValue { get; set; }
  5827. // public DateTime UpdateTime { get; set; }
  5828. // public int State { get; set; }
  5829. //}
  5830. //public class SharedSpeedFileHelper
  5831. //{
  5832. // private static readonly object _lockObj = new object();
  5833. // string directoryPath = @"Z:\\XTM\\Speed";
  5834. // //public SharedSpeedFileHelper()
  5835. // //{
  5836. // // try
  5837. // // {
  5838. // // string directoryPath = @"Z:\\1111\\2222\\3333";
  5839. // // // 确保目录存在
  5840. // // if (!Directory.Exists(directoryPath))
  5841. // // Directory.CreateDirectory(directoryPath);
  5842. // // _filePath = Path.Combine(directoryPath, "SharedSpeedData.json");
  5843. // // }
  5844. // // catch
  5845. // // {
  5846. // // LogHelper.WriteLogInfo("Z盘路径不存在");
  5847. // // }
  5848. // //}
  5849. // // 写入速度数据
  5850. // public void WriteSpeedData(string speed, int state)
  5851. // {
  5852. // lock (_lockObj)
  5853. // {
  5854. // try
  5855. // {
  5856. // var data = new SpeedData
  5857. // {
  5858. // SpeedValue = speed,
  5859. // UpdateTime = DateTime.Now,
  5860. // State = state
  5861. // };
  5862. // string json = JsonSerializer.Serialize(data, new JsonSerializerOptions
  5863. // {
  5864. // WriteIndented = true
  5865. // });
  5866. // // 确保目录存在
  5867. // if (!Directory.Exists(directoryPath))
  5868. // Directory.CreateDirectory(directoryPath);
  5869. // string _filePath = Path.Combine(directoryPath, "SharedSpeedData.json");
  5870. // File.WriteAllText(_filePath, json, Encoding.UTF8);
  5871. // }
  5872. // catch (Exception ex)
  5873. // {
  5874. // throw new InvalidOperationException($"写入速度文件失败: {ex.Message}", ex);
  5875. // }
  5876. // }
  5877. // }
  5878. // // 读取速度数据
  5879. // public SpeedData ReadSpeedData()
  5880. // {
  5881. // lock (_lockObj)
  5882. // {
  5883. // try
  5884. // {
  5885. // // 确保目录存在
  5886. // if (!Directory.Exists(directoryPath))
  5887. // {
  5888. // return null;
  5889. // }
  5890. // string _filePath = Path.Combine(directoryPath, "SharedSpeedData.json");
  5891. // string json = File.ReadAllText(_filePath, Encoding.UTF8);
  5892. // return JsonSerializer.Deserialize<SpeedData>(json);
  5893. // }
  5894. // catch (Exception ex)
  5895. // {
  5896. // throw new InvalidOperationException($"读取速度文件失败: {ex.Message}", ex);
  5897. // }
  5898. // }
  5899. // }
  5900. //}
  5901. //#endregion
  5902. #endregion
  5903. }
  5904. }