From 26145278b69be82a842c01e1af303e25316439b1 Mon Sep 17 00:00:00 2001 From: sige Date: Mon, 17 Jun 2024 17:23:21 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=AF=E5=8A=A8=E6=97=B6=E5=85=B3=E9=97=AD?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E4=BB=BB=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.db | Bin 294912 -> 405504 bytes .../a800/BoditechA800ApplicationRunner.java | 10 +++- .../iflytop/a800/controller/DemoController.java | 2 +- .../com/iflytop/a800/device/DeviceComponent.java | 55 +++++++++++++++++++ .../java/com/iflytop/a800/device/Incubator.java | 13 +++-- src/main/java/com/iflytop/a800/model/MdbTest.java | 44 +++++++++++++++ .../a800/model/MdbTubeRackTestTaskTube.java | 5 +- .../java/com/iflytop/a800/task/TubeRackTask.java | 5 +- .../java/com/iflytop/a800/task/TubeTestTask.java | 59 +++++++++++++++++++-- 9 files changed, 178 insertions(+), 15 deletions(-) create mode 100644 src/main/java/com/iflytop/a800/device/DeviceComponent.java diff --git a/app.db b/app.db index 2230299cda46a1f740354bd41ca95597f7cceb4a..3fb31ded0b8836f6bb111a9c7e2a638ef670946c 100644 GIT binary patch delta 7454 zcmd5>ZEPIH8Q#4;`|Pvt))&XUII&~L5JJ)np4plG7-*X~j&Y2Qoev*@rU7QZXdv;C z*g-_Jxw!d2Ar1ju%aRhQw4(e#szM2>p^cOl6{M>DfuK@R6(B<5Uula}wGy9w_xut2 zu<^P-P%S;@^X=^HbML(KywAKoa%9PoE6W~RzQnjFNsk7{g+-Uz3p2XUTiWidVikWnmc6ia?1Q4J_Db>e*-G_T`b{;JJ_}Dhncir{ zo9Y#NS+wLx!qq%(hTXk@_OEDjOFip6tl>Vq@w zGU+5Sr2;KZLc7iqr9>>1R@7scp57)NV_DtNMfLx~fZ+O2uo5RQjXXz3Kt!jmqbwdjtHK zd}BO)PVR!4UG-?gP$JviEgxSyBJ90h&>qOmLH3l=EVl<+&&sQV!fB;4xcihsk|T%i z_u5(qyKWy0&YYE(1@}EAXM@Y9m1lxG$CQTT(KUM$*_IahM04=@Q6($eLH3xkCHUaS za!auBQKdF$eN;&V8y->Wg3nGViRJxb-{f@bQ_0rWw&BwHb>>|!c>T1}5?uO;ydwD7 zab@Kldxo5YHmvK8z4?)zA=i7bt#!}Phm%a8i05{U%yWJ7!2@DsPkw0n za`5+um2B|aV@kt#{|_O;l{a-&W(U>=AD)z(fOyvOM_H zBg)EU7_L->d+=!cmPFQZJ6;3Jt z8o%_U{B}h={THdK2!rG5&!uZ%HChr6^dz#Q)lRVOq_Q&j#hKDwm&TO!ag&mLMJ%@l z|2d}ARfKA>3vSqX;%WI;Psd_7`M6Y>d`ha_pL}Y(_Vw7AWZlsnv4mQm$voVkZS5Sy zT5$Ao>{-|gYu}E&TWM+-euBH+jY>_?Y7fDP8;aDn{Yi!P}s&34t8d8K1Y-qZR9NWXN-33P6 zc6>xlOfX}Xt8rp$#Pq|R%q`bJO!o;AjwcXzJ(t;zVR2XN+;o?IYv0X1{XILjbZs8W zhkF_8lwo>nM}MxPZ&w>>+ue~X3=Y)FlAdc^ky#~|2r!N6Fw{UC6CW|dG?CygLD=)K zuDO(JzCS7z5|gZ>-!v!dLR8vX7I8qk%NMRN-^%Um z=o#$k@1C)6thz)1VxOE9`~U61lg}+gNtwwfPvy+uK%sgT18nPn7!(#G9VA}PAU=zMp<&7`-9#n@*<#doki{&} zE-XM(FtJ@y9)rT7#EW31oPjcnfn~VV_puJo1&hRN2AhyG8#xB2CdU>i=xh~$bX^n! zYy|&oQ5x%O(vPWcspr%0rC(Net0&U;s0{SHH(dxFN|YU$3m@$F2v%O`m#>Z*+F_cXss! zPp(i_ZLw^VV#|bdH@JbAZ*T-62=YTb!(bE>Zg^4V4CE$dO+jcjb-86AVt8QGO$Q^( z^K_(fL)e;U8%&GDaJqy{6pp^3WNj|joJmcT?0KI8^=na&nGD3`CZ(<4H#LYN$8bb} z!VYm0$kr*;M9-j_AqsP{@f}4(J6Ax*=9acdLYLG8< zWP8k~hOS$Vp)F$0bK#tn8X#I0MINL9=$Q+NMY)Z@-Vlpm8*9v3#GJJ)FsFuX&ow+3 zG00X(FQ}Rz%sQfs2;w@R(cE9eoZk!Qv}~I?1XB=N7nC2~BF=pXFLl5PU}8ExRKdub z>TfMd)6$Z%vh;iEc~II=VL@}RYV5q}J0p8b8XF}gOBx#`&n7fBO7@gAHcCpAG&agQ zmozq9yuw1OH=(f+mZYSyQ3SE1u~RB{-IvK+3T&~gzACA&UdXimMm4!ykz18%_=546 z!*^`mKG4~1bho%0X6|T z0Gk1wfSUnbfGvP-z%76tKp&tN&=0s3uoW->*bdkR7zFG9>;&8f$N}yE+z!|U_%>j- zBwZ(c2j1KTxDy}%cLO#8HUKyP1KJ@%gX*)-E3IW;;p&(9zkXM@Ki-t8dO}Jj*2y)m zslDkRrQS`RtbVh)Ikh%%C9w`RYdTRFrAalHOQkZ|RjZoo<#_Bq0Vg!eWCW^$2ZBxv zhB)&*1P5QJ9fHFzEsBN0VxfKFuI3_N_?qbm z&0`Ljl!f~UfY-r?ql&+B7+R<_cB-xwZ3>t0*UD_$GK&8rnKYFVh1v!zWrvalwX9S(LCj9VM%?Wm+PJ{rpEK<_uDcx_&Oz0PQ|JrDz$c zs_LuUmqU3URI92it#k{b`^1i8L}*3giQyG&rGWX zs8;oy5ep?XUPcbwwarQCJQI?`*hZFs-hhB*Hhs=4n}Oml+&U;H2j+L8r%CWka*Ch- z_|&}QlrnO*?L*7dg#M-l4J^h4{8z-qa4iHRVJVH$`+3_eEQ?lbxQhLIUN2x|7J07Jn mlI@Xp1T+h$4hk0X+m%G*bJ`tdDiF>x>Kh zmne2NJMX>U_vX8Q@9lqW(f<9N2T$+3aHFCq8{lX9&(1^3$s+i6#psV(;Jb|ee*DDN z|D(U(_RjZiyhWdQt)S?D&ctW>*Ngq6t+Mq5^@ zJijV_)-m&}y?u1=*jS92(T^zlOZpL5;&FZQNUu8h>1=!UuTf#Y`sYkGcj(cTlbz%0 zlj>7F?aS1O(ah5m`*XdMfBCX{c6p`tJEc80pyXf7D=p9E2DAq%cUQKxeYI^{>Ehzs z`gz))itVk>6qaQVt4Fey@{`CosIG!_-pEd#at|yyA=MWrF3N7w4=i0<=yqN8c6Fb0 zcKgwIq+X=*3%T#-vg^;-KwZ=K z7^ld!Jc^h}8FE|~BW^J>zyaZ&2&nY1ZwM24*fkKt0Y?&J7h#MoVGAau>qhF5?BeKK zXJoYv0dox34jA%Wj1lvNg>26Z5M`7Kn_!bmC+(8whrVTdo@Lo6U>F1pe2IkcT_jxQ zW61*-i&U#!wr1nbjRXCodyAK@85mr%ceKPoLXs$!WRg$e&fK#9UG#T zmt?C06l7zjAczPl5RVlk>OOf<^j$&O2({>p47b55KGhs~zQU)d`h!Pv* zvabZ5ga- zW6QQUaZuoM2KLVd$Vp7(yG)vf9dLuCvi~U^eF@gwPFzli$xMVPxD&H%f@}$j;)0mm zGO0s6JH4EJmyGU>{{C)eaTn9?&<^TH^s@FteMoy<8_{0^f8L~p7i0(3rWRahz@>O# z8mlbE1JjsVYdkPaV?c#?WE!i;#{<)-x+NYM>n}W!0(0@mG+N2V1Ji`W%=y{D;&h-p zZ@x%Zf&8NC&nfzIkRG4bO<}1mgJ)GvO=AFCw{Kb3w_^u{t;wUk+1FNzG?QY$yp~b) zuj^d)g1|$}i*4SfKJpz4V~Dk`K^z0GThrga z)-(rMOKld##1+19kQWH>Xcalg( zw^nZ*aAqN6E5)Kha`V{+wU>ovWqkU8du=r4MQ{jTv zf9Dsqexs$eb$j-`+#kSVex0q34{a}WFI%P_C?*xoOdT}yp+CC&u)1NUKCzSfB!hQM z7-~;+&%#%zEOeF_GZB8Q; zX(kj|lTIiyE7a_3Ip+)h*bTe)ReN^!eQxLSN~x!(+CX6ZpxTpzkaGH=HK*mbZOeE2 zy-A_WkE@4=S<_N^n62NoWxlDj`BZwzwoB)mN}5k4YqxEhncA?jZ&uq6e-mjh;y?URTkNOX(IC>>gUoYI;U+5mMjKqps+Y)y$IO&AC;G=PXuP=0ujHtKQ z{4sfug$K!p9DG=rbW6!salaHnzx3niD~G_XKJ}n_YJPQJzI)4sHJRSJSA8aPJ*PjQt<+a(hbtdKM0v9k(tOL{f>V&p#*@;<`T4?p*fg2Y zmPD|HWjPmedB@TPMC~xnsC5Y_McBR-8aG9QcQ%zuKc9;+>l5n&@@kkav1Ve3k0Iq9 zm+{V=&E7F{kk`wKUIy*}N?Rywp*`*SpjOVNsZo+jF^$5KO0ljIY5KyFLNQEJPb8IM znwlV~6w{>jO63T;w89-Rrj_D!61T=OgH7snJP|R7j z8+YgibZRaGW`jFGRd^=xTuK7Zb-w72)hL6_S5|R#=(4p5f3W$QVjY$zfH-kOA2<)< z#tkVH*U~g?WEzBck_6HfZc4D$+WK?BTI;|#v7sh3O+=W0HrN0_=zB4;LW6sb=`&_P z@0xCBg+^e7IxrJzci%Ju;D=a%7-tT$1KUKdaIhN~t^`VF8Y?`(Ys@zS%h!PcFT@4V zIVkWvP?-abv-F|b_PxMi@JxC(o(5}x71rylr4d+59hgTPKM>LahC({Pq;MZB1&VIl z076BWm`Za#uzIXq4J(|hvs@jR<54WJ2#^(EXiQ9O0mVY0?=q#dz*2$Bnt6>4c2*CT zZM3m$j1^8urLfmTE;xDu^ueb0Blz#*;q00GHwz> z8W?oMNeJYT19X>-9RY0%5U9S*C^W4p!5U$y307+j%K?&$0(*H&ooYuWY5@u!xLF>l0MT|UoCsqnNBmyNwO!O(!0@2@v+_$ z+M{w*(eKx(_FL^5jaH6=*50awJYPs?j|K7`yk%-ynhImKCwFqmw2|p@%?pA0Xj*X0 z&YLX?Q!pQHHUZhCq$pLwnERNoCT?01dzl2~S|v@L(+DKtKEnA~iCc$!HG$cqq^Xh` z!OTy7ESaW@P8L+h7gYJ!W6F(PX5my};xh5H|HEZq+DuRLiMb4br0F6*qRRlvN9&!^ zxeUN8pz~Zv<9X6$nozGZN#>->97C|5beX9`iIZ98m@HGiSt%8xY^CdMeXO#*?dRo} zv^Pqx7T+t47b7UpZYhRWl?sEvH+3m+2<0>B2PkkE+#Ik>A4xkPP~aP$bbKP&FHqZi?V$LmMnb=8l9yuH%*olw#=K##^27cF?!QB@)4hDNdw(A*iEy(a-wgZ<N E0CiwLkpKVy diff --git a/src/main/java/com/iflytop/a800/BoditechA800ApplicationRunner.java b/src/main/java/com/iflytop/a800/BoditechA800ApplicationRunner.java index 28a72b2..ee4354d 100644 --- a/src/main/java/com/iflytop/a800/BoditechA800ApplicationRunner.java +++ b/src/main/java/com/iflytop/a800/BoditechA800ApplicationRunner.java @@ -1,4 +1,5 @@ package com.iflytop.a800; +import com.iflytop.a800.model.MdbTubeRackTestTask; import com.iflytop.a800.model.MdbTubeRackTestTaskTube; import com.iflytop.uf.UfActiveRecord; import com.iflytop.uf.model.UfMdbDictItem; @@ -7,9 +8,7 @@ import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; - import java.util.Map; - @Order(10) @Component public class BoditechA800ApplicationRunner implements ApplicationRunner { @@ -23,5 +22,12 @@ public class BoditechA800ApplicationRunner implements ApplicationRunner { UfActiveRecord.updateAll(MdbTubeRackTestTaskTube.class, cancelStatus, Map.of("status", "NEW")); UfActiveRecord.updateAll(MdbTubeRackTestTaskTube.class, cancelStatus, Map.of("status", "WAITING")); UfActiveRecord.updateAll(MdbTubeRackTestTaskTube.class, cancelStatus, Map.of("status", "EXECUTING")); + + // 将所有试管架任务状态改为已取消 + cancelStatus = Map.of("status", UfMdbDictItem.getValue("TUBE_RACK_TASK_STATUS", "CANCELED")); + UfActiveRecord.updateAll(MdbTubeRackTestTask.class, cancelStatus, Map.of("status", "CONFIGURING")); + UfActiveRecord.updateAll(MdbTubeRackTestTask.class, cancelStatus, Map.of("status", "WAITING")); + UfActiveRecord.updateAll(MdbTubeRackTestTask.class, cancelStatus, Map.of("status", "PROCESSING")); + UfActiveRecord.updateAll(MdbTubeRackTestTask.class, cancelStatus, Map.of("status", "ERROR")); } } diff --git a/src/main/java/com/iflytop/a800/controller/DemoController.java b/src/main/java/com/iflytop/a800/controller/DemoController.java index 7ec6ff5..e91c21b 100644 --- a/src/main/java/com/iflytop/a800/controller/DemoController.java +++ b/src/main/java/com/iflytop/a800/controller/DemoController.java @@ -126,7 +126,7 @@ public class DemoController extends UfApiControllerBase { for ( int i = 0; i < 20; i++ ) { var slot = new IncubatorSlot(); slot.index = i; - incubator.exitToScanner(slot); + incubator.exitCardToScanner(slot); } return this.success(); } diff --git a/src/main/java/com/iflytop/a800/device/DeviceComponent.java b/src/main/java/com/iflytop/a800/device/DeviceComponent.java new file mode 100644 index 0000000..f88f447 --- /dev/null +++ b/src/main/java/com/iflytop/a800/device/DeviceComponent.java @@ -0,0 +1,55 @@ +package com.iflytop.a800.device; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.util.ArrayList; +import java.util.List; +abstract public class DeviceComponent { + // logger + public static final Logger LOG = LoggerFactory.getLogger(DeviceComponent.class); + // lock object class + public static class DeviceComponentLock { + public String name; + } + + // locks + private final List locks = new ArrayList<>(); + + // lock + public DeviceComponentLock lock( String name ) { + LOG.info("LOCK : {}", name); + + var lock = new DeviceComponentLock(); + lock.name = name; + synchronized ( this.locks ) { + this.locks.add(lock); + if ( 1 == this.locks.size() ) { + return lock; + } + } + + LOG.info("LOCK WAITING : {}", name); + try { + lock.wait(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + LOG.info("LOCK DONE : {}", name); + return lock; + } + + // unlock + public void unlock( DeviceComponentLock lock ) { + synchronized ( this.locks ) { + LOG.info("UNLOCK : {}", lock.name); + this.locks.remove(lock); + if ( this.locks.isEmpty() ) { + return ; + } + + var next = this.locks.get(0); + LOG.info("NOTIFY NEXT : {}", next.name); + next.notifyAll(); + } + } +} diff --git a/src/main/java/com/iflytop/a800/device/Incubator.java b/src/main/java/com/iflytop/a800/device/Incubator.java index 7f76020..a48babb 100644 --- a/src/main/java/com/iflytop/a800/device/Incubator.java +++ b/src/main/java/com/iflytop/a800/device/Incubator.java @@ -6,7 +6,7 @@ import com.iflytop.uf.model.UfMdbOption; import java.util.ArrayList; import java.util.List; import java.util.Map; -public class Incubator { +public class Incubator extends DeviceComponent { // 槽位 private final List slots; // 槽位起始索引 @@ -23,11 +23,10 @@ public class Incubator { } } - public void lock() {} - public void unlock() {} - // 推送新卡片 public IncubatorSlot pushNewCard(TestCard card) { + var lock = this.lock("PushNewCard"); + IncubatorSlot slot = null; for ( int i=0; i<20; i++ ) { var tmpSlot = this.slots.get(this.slotStartIndex); @@ -57,16 +56,20 @@ public class Incubator { ); UfCmdSnippetExecutor.execute("IncubatorTestCardPushIn", params); slot.card = card; + + this.unlock(lock); return slot; } // 退出到扫描 - public void exitToScanner( IncubatorSlot slot ) { + public void exitCardToScanner( IncubatorSlot slot ) { + var lock = this.lock("ExitCardToScanner"); Integer startPos = UfMdbOption.getInteger("IncubatorSlotExitStartPos"); Integer distance = UfMdbOption.getInteger("IncubatorSlotExitDistance"); Integer slotPos = startPos + distance * slot.index; Map params = Map.of("slot", slotPos); UfCmdSnippetExecutor.execute("IncubatorTestCardExitToScanner", params); slot.card = null; + this.unlock(lock); } } diff --git a/src/main/java/com/iflytop/a800/model/MdbTest.java b/src/main/java/com/iflytop/a800/model/MdbTest.java index d91448e..b9702ca 100644 --- a/src/main/java/com/iflytop/a800/model/MdbTest.java +++ b/src/main/java/com/iflytop/a800/model/MdbTest.java @@ -1,24 +1,68 @@ package com.iflytop.a800.model; import com.iflytop.uf.UfActiveRecord; import com.iflytop.uf.UfActiveRecordField; +import com.iflytop.uf.model.UfMdbRuntimeVariable; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + public class MdbTest extends UfActiveRecord { @UfActiveRecordField public String tubeId; @UfActiveRecordField + public String sampleUid; + + @UfActiveRecordField + public String sampleType; + + @UfActiveRecordField public String isSamplingFinished; @UfActiveRecordField public String projectCode; @UfActiveRecordField + public String projectName; + + @UfActiveRecordField + public String serialCode; + + @UfActiveRecordField + public String barCode; + + @UfActiveRecordField public String materialLotCode; @UfActiveRecordField + public Integer incubateSlotIndex; + + @UfActiveRecordField + public Integer incubateStartedAt; + + @UfActiveRecordField + public Integer incubateDuration; + + @UfActiveRecordField public String result; // get table name public static String getTableName() { return "app_tests"; } + + // 生成序列号 + public static String generateSerialCode() { + var count = UfMdbRuntimeVariable.getInteger("TestCountOfDay", 0); + var date = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyMMdd")); + var runtimeDate = UfMdbRuntimeVariable.getString("TestSerialDate", ""); + if (!date.equals(runtimeDate)) { + UfMdbRuntimeVariable.setString("TestSerialDate", date); + count = 0; + } + + count ++; + UfMdbRuntimeVariable.setInteger("TestCountOfDay", count); + return String.format("%s-%03d", date, count); + } } diff --git a/src/main/java/com/iflytop/a800/model/MdbTubeRackTestTaskTube.java b/src/main/java/com/iflytop/a800/model/MdbTubeRackTestTaskTube.java index d9c0869..7e9ae84 100644 --- a/src/main/java/com/iflytop/a800/model/MdbTubeRackTestTaskTube.java +++ b/src/main/java/com/iflytop/a800/model/MdbTubeRackTestTaskTube.java @@ -3,10 +3,8 @@ import com.iflytop.a800.device.Device; import com.iflytop.uf.UfActiveRecord; import com.iflytop.uf.UfActiveRecordField; import com.iflytop.uf.util.UfJsonHelper; - import java.util.ArrayList; import java.util.List; - public class MdbTubeRackTestTaskTube extends UfActiveRecord { @UfActiveRecordField public String rackId; @@ -38,6 +36,9 @@ public class MdbTubeRackTestTaskTube extends UfActiveRecord { @UfActiveRecordField public String status; + @UfActiveRecordField + public String type = ""; + // get table name public static String getTableName() { return "app_tube_rack_test_task_tubes"; diff --git a/src/main/java/com/iflytop/a800/task/TubeRackTask.java b/src/main/java/com/iflytop/a800/task/TubeRackTask.java index c26c2f1..c08d997 100644 --- a/src/main/java/com/iflytop/a800/task/TubeRackTask.java +++ b/src/main/java/com/iflytop/a800/task/TubeRackTask.java @@ -35,10 +35,11 @@ public class TubeRackTask extends TaskBase { feeder.feed(); this.samplingTubes = new ArrayList<>(); - // test tube rack TestTubeRack tubeRack = new TestTubeRack(); tubeRack.type = feeder.readTubeRackType(); tubeRack.tubes = new ArrayList<>(); + this.taskModel.tubeType = tubeRack.type; + this.taskModel.save(); for (int i = 0; i < 10; i++) { var tube = new TestTube(); tube.index = i; @@ -78,6 +79,8 @@ public class TubeRackTask extends TaskBase { taskMan.append(testTask); } + tubeModel.type = tube.type; + tubeModel.barCode = tube.barCode; tubeModel.status = UfMdbDictItem.getValue("TUBE_STATUS", "WAITING"); tubeModel.save(); } diff --git a/src/main/java/com/iflytop/a800/task/TubeTestTask.java b/src/main/java/com/iflytop/a800/task/TubeTestTask.java index 10b3c08..0d611d7 100644 --- a/src/main/java/com/iflytop/a800/task/TubeTestTask.java +++ b/src/main/java/com/iflytop/a800/task/TubeTestTask.java @@ -71,8 +71,15 @@ public class TubeTestTask extends TaskBase { // 测试记录 this.test = new MdbTest(); this.test.tubeId = this.tubeModel.id; + this.test.sampleUid = this.tubeModel.sampleUid; + this.test.sampleType = this.tubeModel.sampleType; this.test.projectCode = this.project.code; + this.test.projectName = this.project.name; this.test.materialLotCode = this.testCard.lotCode; + this.test.barCode = this.tubeModel.barCode; + this.test.serialCode = MdbTest.generateSerialCode(); + this.test.incubateStartedAt = 0; + this.test.incubateDuration = 0; this.test.isSamplingFinished = "no"; this.test.save(); @@ -109,6 +116,8 @@ public class TubeTestTask extends TaskBase { this.log("测试卡推送至孵育盘 :开始"); this.incubatorSlot = device.incubator.pushNewCard(this.testCard); this.testCard.incubatorSlotIndex = this.incubatorSlot.index; + this.test.incubateSlotIndex = this.testCard.incubatorSlotIndex; + this.test.save(); this.log("测试卡推送至孵育盘 : 完成 -> Slot={}", this.testCard.incubatorSlotIndex); synchronized ( this.testCard ) { this.testCard.notifyAll(); @@ -180,12 +189,19 @@ public class TubeTestTask extends TaskBase { this.log("试管采样结束"); this.tubeModel.status = UfMdbDictItem.getValue("TUBE_STATUS", "FINISHED"); this.tubeModel.save(); + this.emit("TubeSamplingFinished"); } } // 摇匀 private void shake( JsonNode stepNode ) { + if ( !this.isFirstTestOfTube() ) { + this.log("非当前试管第一个项目,无需摇匀操作"); + return ; + } + int count = stepNode.get("count").asInt(); + this.log("摇匀 : {}", count); UfCmdSnippetExecutor.execute("SampleTestShakePrepare"); for ( int i=0; i