service.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. package cabinet_pkg
  2. import (
  3. "dy-admin/internal/pcmserver/bus/cabinet_pkg/dataProto"
  4. "dy-admin/internal/pcmserver/bus/model"
  5. "dy-admin/internal/pcmserver/global"
  6. "dy-admin/internal/pcmserver/pkg/code"
  7. "dy-admin/pkg/log"
  8. "dy-admin/pkg/rescode"
  9. "encoding/hex"
  10. "fmt"
  11. "go.uber.org/zap"
  12. "strings"
  13. "time"
  14. )
  15. // AddCabinet 添加柜子
  16. // info 柜子基础信息
  17. // cabinetConnectChan 柜子连接状态
  18. // gridStatusChan 柜子所有格子状态回传通道
  19. func AddCabinet(cabinetInfo model.Cabinet, cabinetConnectChan chan<- *dataProto.CabinetConnect,
  20. gridStatusChan chan<- *dataProto.GridStatsProto, openStatusChan chan<- *dataProto.GridLockStatusProto) error {
  21. if cabinets == nil {
  22. return fmt.Errorf("cabinets is nil")
  23. }
  24. cb := newCabinet(cabinetInfo, cabinetConnectChan, gridStatusChan, openStatusChan)
  25. cabinets.setCabinet(cabinetInfo.ID, cb)
  26. return nil
  27. }
  28. // DelCabinet 删除柜子
  29. func DelCabinet(cabinetId int) error {
  30. if cabinets == nil {
  31. return fmt.Errorf("cabinets is nil")
  32. }
  33. cab, exists := cabinets.getCabinet(cabinetId)
  34. if !exists {
  35. return nil
  36. }
  37. if cab != nil {
  38. if cab.conn != nil {
  39. err := cab.conn.Close()
  40. if err != nil {
  41. return err
  42. }
  43. }
  44. }
  45. cabinets.deleteCabinet(cabinetId)
  46. return nil
  47. }
  48. func cabinetPreCheck(cabinetId int) (*cabinet, error) {
  49. if cabinets == nil {
  50. return nil, fmt.Errorf("cabinets is nil")
  51. }
  52. cab, ok := cabinets.getCabinet(cabinetId)
  53. if !ok {
  54. err := fmt.Errorf("cabinetID %d not found", cabinetId)
  55. return nil, rescode.RegisterErrorWithCause(err, code.ErrCodeMap[code.ErrCabinetMemNotFoundCode])
  56. }
  57. if !cab.memInfo.IsConnect {
  58. err := fmt.Errorf("cabinetID %d not connected", cabinetId)
  59. return nil, rescode.RegisterErrorWithCause(err, code.ErrCodeMap[code.ErrCabinetNotConnectCode])
  60. }
  61. return cab, nil
  62. }
  63. func SetCabinetNumber(cabinetId int) error {
  64. cab, err := cabinetPreCheck(cabinetId)
  65. if err != nil {
  66. return err
  67. }
  68. ccp := &dataProto.CabinetConfigProto{
  69. PkgLength: dataProto.PkgLengthCabinetConfig,
  70. StartSymbol: dataProto.StartSymbolCabinetConfig,
  71. Cmd: dataProto.CmdCabinetConfig,
  72. CabinetNumber: cab.memInfo.CabinetNum,
  73. CabinetGridCount: cab.memInfo.GridCount,
  74. CRCCode: 0x1DC0,
  75. }
  76. encodeBytes, err := dataProto.CabinetConfigProtoEncode(ccp)
  77. if err != nil {
  78. return rescode.RegisterErrorWithCause(err, code.ErrCodeMap[code.ErrCabinetDeviceCode])
  79. }
  80. tcpServer.WriteData(cab.conn, encodeBytes)
  81. // 记录下发设置柜子编号指令
  82. deviceLogChan <- &MsgLog{
  83. CabinetID: cabinetId,
  84. MsgType: model.MsgTypeSend,
  85. MsgName: "设置柜子编号指令",
  86. Message: encodeBytes,
  87. }
  88. err = waitCabinetConfigResponse(cab.responseChannels.cabinetConfigResChannel, cab.memInfo.CabinetNum, 10)
  89. if err != nil {
  90. return rescode.RegisterErrorWithCause(err, code.ErrCodeMap[code.ErrCabinetTimeoutCode])
  91. }
  92. return nil
  93. }
  94. // EnableOpenDoor 允许开门
  95. func EnableOpenDoor(cabinetId int, uptMem bool) error {
  96. cab, err := cabinetPreCheck(cabinetId)
  97. if err != nil {
  98. return err
  99. }
  100. if !IsHumanization() {
  101. // 强制管理 下发允许开门指令
  102. controlProto := &dataProto.DoorControlProto{
  103. PkgLength: dataProto.PkgLengthDoorControl,
  104. StartSymbol: dataProto.StartSymbolDoorControl,
  105. CabinetNumber: cab.memInfo.CabinetNum,
  106. Cmd: dataProto.CmdDoorControlEnable,
  107. }
  108. controlProtoBytes, err := dataProto.DoorControlProtoEncode(controlProto)
  109. if err != nil {
  110. tips := fmt.Sprintf("cabinetId:%d", cabinetId)
  111. return rescode.RegisterErrorWithMessage(err, tips, code.ErrCodeMap[code.ErrCabinetDeviceCode])
  112. }
  113. //发送
  114. tcpServer.WriteData(cab.conn, controlProtoBytes)
  115. // 记录下发允许开门指令
  116. deviceLogChan <- &MsgLog{
  117. CabinetID: cabinetId,
  118. MsgType: model.MsgTypeSend,
  119. MsgName: "允许开门指令",
  120. Message: controlProtoBytes,
  121. }
  122. err = waitDoorControlResponse(cab.responseChannels.doorControlResChannel, dataProto.CmdDoorControlEnable, 10)
  123. if err != nil {
  124. tips := fmt.Sprintf("cabinetId:%d", cabinetId)
  125. return rescode.RegisterErrorWithMessage(err, tips, code.ErrCodeMap[code.ErrCabinetTimeoutCode])
  126. }
  127. }
  128. //更新内存柜子信息未允许开启状态
  129. if uptMem {
  130. cab.memInfo.IsAllowOpen = true
  131. }
  132. // 发送获取柜子所有消息的指令
  133. go func() {
  134. // 柜子要求.发送禁止柜门后1分钟后再获取状态。
  135. time.Sleep(time.Second * 60)
  136. err = GetCabinetStatus(cabinetId)
  137. if err != nil {
  138. log.Error("获取柜门信息失败", zap.Error(err))
  139. }
  140. }()
  141. return nil
  142. }
  143. // DisableOpenDoor 禁止打开所有柜门
  144. func DisableOpenDoor(cabinetId int) error {
  145. cab, err := cabinetPreCheck(cabinetId)
  146. if err != nil {
  147. return err
  148. }
  149. if !IsHumanization() {
  150. // 强制管理
  151. controlProto := &dataProto.DoorControlProto{
  152. PkgLength: dataProto.PkgLengthDoorControl,
  153. StartSymbol: dataProto.StartSymbolDoorControl,
  154. CabinetNumber: cab.memInfo.CabinetNum,
  155. Cmd: dataProto.CmdDoorControlDisable,
  156. }
  157. controlProtoBytes, err := dataProto.DoorControlProtoEncode(controlProto)
  158. if err != nil {
  159. tips := fmt.Sprintf("cabinetId:%d", cabinetId)
  160. return rescode.RegisterErrorWithMessage(err, tips, code.ErrCodeMap[code.ErrCabinetDeviceCode])
  161. }
  162. //发送
  163. tcpServer.WriteData(cab.conn, controlProtoBytes)
  164. // 记录下发禁止开门指令
  165. deviceLogChan <- &MsgLog{
  166. CabinetID: cabinetId,
  167. MsgType: model.MsgTypeSend,
  168. MsgName: "禁止开门指令",
  169. Message: controlProtoBytes,
  170. }
  171. err = waitDoorControlResponse(cab.responseChannels.doorControlResChannel, dataProto.CmdDoorControlDisable, 10)
  172. if err != nil {
  173. tips := fmt.Sprintf("cabinetId:%d", cabinetId)
  174. return rescode.RegisterErrorWithMessage(err, tips, code.ErrCodeMap[code.ErrCabinetTimeoutCode])
  175. }
  176. }
  177. //更新内存柜子信息未允许开启状态
  178. cab.memInfo.IsAllowOpen = false
  179. // 发送获取柜子所有消息的指令
  180. go func() {
  181. // 柜子要求.发送禁止柜门后1分钟后再获取状态。
  182. time.Sleep(time.Second * 60)
  183. err = GetCabinetStatus(cabinetId)
  184. if err != nil {
  185. log.Error("获取柜门信息失败", zap.Error(err))
  186. }
  187. }()
  188. return nil
  189. }
  190. func EnableGrid(cabinetId int, gridNum uint16) error {
  191. cab, err := cabinetPreCheck(cabinetId)
  192. if err != nil {
  193. return err
  194. }
  195. controlProto := &dataProto.GridControlProto{
  196. PkgLength: dataProto.PkgLengthGridControl,
  197. StartSymbol: dataProto.StartSymbolGridControl,
  198. CabinetNumber: cab.memInfo.CabinetNum,
  199. GridNumber: gridNum,
  200. Cmd: dataProto.CmdGridControlEnable,
  201. }
  202. controlProtoBytes, err := dataProto.GridControlProtoEncode(controlProto)
  203. if err != nil {
  204. return rescode.RegisterErrorWithCause(err, code.ErrCodeMap[code.ErrCabinetDeviceCode])
  205. }
  206. // 记录下发允许打开格子指令
  207. deviceLogChan <- &MsgLog{
  208. CabinetID: cabinetId,
  209. MsgType: model.MsgTypeSend,
  210. MsgName: fmt.Sprintf("允许打开%d号格子指令", gridNum),
  211. Message: controlProtoBytes,
  212. }
  213. //发送
  214. tcpServer.WriteData(cab.conn, controlProtoBytes)
  215. err = waitGridControlResponse(cab.responseChannels.gridControlResChannel, dataProto.CmdGridControlEnable, 10)
  216. if err != nil {
  217. return rescode.RegisterErrorWithCause(err, code.ErrCodeMap[code.ErrCabinetTimeoutCode])
  218. }
  219. return nil
  220. }
  221. func DisableGrid(cabinetId int, gridNum uint16) error {
  222. cab, err := cabinetPreCheck(cabinetId)
  223. if err != nil {
  224. return err
  225. }
  226. controlProto := &dataProto.GridControlProto{
  227. PkgLength: dataProto.PkgLengthGridControl,
  228. StartSymbol: dataProto.StartSymbolGridControl,
  229. CabinetNumber: cab.memInfo.CabinetNum,
  230. GridNumber: gridNum,
  231. Cmd: dataProto.CmdGridControlDisable,
  232. }
  233. controlProtoBytes, err := dataProto.GridControlProtoEncode(controlProto)
  234. if err != nil {
  235. return rescode.RegisterErrorWithCause(err, code.ErrCodeMap[code.ErrCabinetDeviceCode])
  236. }
  237. //发送
  238. tcpServer.WriteData(cab.conn, controlProtoBytes)
  239. // 记录下发禁止打开格子指令
  240. deviceLogChan <- &MsgLog{
  241. CabinetID: cabinetId,
  242. MsgType: model.MsgTypeSend,
  243. MsgName: fmt.Sprintf("禁止打开%d号格子指令", gridNum),
  244. Message: controlProtoBytes,
  245. }
  246. err = waitGridControlResponse(cab.responseChannels.gridControlResChannel, dataProto.CmdGridControlDisable, 10)
  247. if err != nil {
  248. return rescode.RegisterErrorWithCause(err, code.ErrCodeMap[code.ErrCabinetTimeoutCode])
  249. }
  250. return nil
  251. }
  252. // OpenDoor 打开指定柜门
  253. func OpenDoor(cabinetId int, gridID uint16) error {
  254. cab, err := cabinetPreCheck(cabinetId)
  255. if err != nil {
  256. return err
  257. }
  258. // 平台可以在禁止时开门
  259. //if !cab.cabinetInfo.IsAllowOpen {
  260. // return fmt.Errorf("此时禁止打开箱门")
  261. //}
  262. openDoor := &dataProto.OpenGridProto{
  263. PkgLength: dataProto.PkgLengthOpenGrid,
  264. StartSymbol: dataProto.StartSymbolOpenGrid,
  265. Cmd: dataProto.CmdOpenGrid,
  266. CabinetNumber: cab.memInfo.CabinetNum,
  267. GridNumber: gridID,
  268. }
  269. //编码
  270. openDoorBytes, err := dataProto.OpenGridProtoEncode(openDoor)
  271. if err != nil {
  272. return rescode.RegisterErrorWithCause(err, code.ErrCodeMap[code.ErrCabinetDeviceCode])
  273. }
  274. //发送
  275. tcpServer.WriteData(cab.conn, openDoorBytes)
  276. // 记录下发打开格子指令
  277. deviceLogChan <- &MsgLog{
  278. CabinetID: cabinetId,
  279. MsgType: model.MsgTypeSend,
  280. MsgName: fmt.Sprintf("打开%d号格子指令", gridID),
  281. Message: openDoorBytes,
  282. }
  283. // 开箱门操作不等待开门结果。 统一由开门状态通道获取箱门的状态。
  284. log.Info("开门命令下发成功", zap.String("cabinetIP", cab.memInfo.CabinetIP), zap.Uint16("number", cab.memInfo.CabinetNum))
  285. return nil
  286. }
  287. // GetCabinetStatus 手动获取柜门所有箱门的状态
  288. func GetCabinetStatus(cabinetId int) error {
  289. cab, err := cabinetPreCheck(cabinetId)
  290. if err != nil {
  291. return err
  292. }
  293. getReq := &dataProto.GetCabinetReq{
  294. PkgLength: dataProto.PkgLengthGetCabinetReq,
  295. StartSymbol: dataProto.StartSymbolGetCabinetReq,
  296. Cmd: dataProto.CmdGetCabinetReq,
  297. CabinetNumber: cab.memInfo.CabinetNum,
  298. }
  299. //编码
  300. openDoorBytes, err := dataProto.GetCabinetReqEncode(getReq)
  301. if err != nil {
  302. return rescode.RegisterErrorWithCause(err, code.ErrCodeMap[code.ErrCabinetDeviceCode])
  303. }
  304. //发送
  305. tcpServer.WriteData(cab.conn, openDoorBytes)
  306. // 记录下发获取所有柜门状态指令
  307. deviceLogChan <- &MsgLog{
  308. CabinetID: cabinetId,
  309. MsgType: model.MsgTypeSend,
  310. MsgName: "获取指定柜子所有格子状态指令",
  311. Message: openDoorBytes,
  312. }
  313. //手动获取箱门状态响应全部由服务层管道读取后统一处理
  314. log.Info("获取柜子信息命令下发成功", zap.String("cabinetIP", cab.memInfo.CabinetIP), zap.Uint16("number", cab.memInfo.CabinetNum))
  315. return nil
  316. }
  317. // SendCabinetDoorStatus 发送柜门此时是否允许开
  318. func SendCabinetDoorStatus(cabinetId int) error {
  319. if cabinets == nil {
  320. return fmt.Errorf("cabinets is nil")
  321. }
  322. cab, ok := cabinets.getCabinet(cabinetId)
  323. if !ok {
  324. return fmt.Errorf("cabinetId %d not found", cabinetId)
  325. }
  326. var doorControlCmd uint8
  327. if cab.memInfo.IsAllowOpen {
  328. doorControlCmd = dataProto.CmdDoorControlEnable
  329. } else {
  330. doorControlCmd = dataProto.CmdDoorControlDisable
  331. }
  332. dcp := &dataProto.DoorControlProto{
  333. PkgLength: dataProto.PkgLengthDoorControl,
  334. StartSymbol: dataProto.StartSymbolDoorControl,
  335. CabinetNumber: cab.memInfo.CabinetNum,
  336. Cmd: doorControlCmd,
  337. }
  338. protoBytes, err := dataProto.DoorControlProtoEncode(dcp)
  339. if err != nil {
  340. return rescode.RegisterErrorWithCause(err, code.ErrCodeMap[code.ErrCabinetDeviceCode])
  341. }
  342. tcpServer.WriteData(cab.conn, protoBytes)
  343. if cab.memInfo.IsAllowOpen {
  344. // 记录下发允许开门指令
  345. deviceLogChan <- &MsgLog{
  346. CabinetID: cabinetId,
  347. MsgType: model.MsgTypeSend,
  348. MsgName: "允许开门指令",
  349. Message: protoBytes,
  350. }
  351. } else {
  352. // 记录下发禁止开门指令
  353. deviceLogChan <- &MsgLog{
  354. CabinetID: cabinetId,
  355. MsgType: model.MsgTypeSend,
  356. MsgName: "禁止开门指令",
  357. Message: protoBytes,
  358. }
  359. }
  360. // 不是页面发起的 不能在这里同步等待
  361. go func() {
  362. err = waitDoorControlResponse(cab.responseChannels.doorControlResChannel, doorControlCmd, 10)
  363. if err != nil {
  364. log.Error("waitDoorControlResponse err", zap.Error(err))
  365. }
  366. }()
  367. return nil
  368. }
  369. func SendPing(cabinetId int) error {
  370. if cabinets == nil {
  371. return fmt.Errorf("cabinets is nil")
  372. }
  373. cab, ok := cabinets.getCabinet(cabinetId)
  374. if !ok {
  375. return fmt.Errorf("cabinetId %d not found", cabinetId)
  376. }
  377. pingBytes, err := hex.DecodeString(dataProto.PingHex)
  378. if err != nil {
  379. return rescode.RegisterErrorWithCause(err, code.ErrCodeMap[code.ErrCabinetDeviceCode])
  380. }
  381. tcpServer.WriteData(cab.conn, pingBytes)
  382. //deviceLogChan <- &MsgLog{
  383. // CabinetID: cabinetId,
  384. // MsgType: model.MsgTypeSend,
  385. // MsgName: "ping",
  386. // Message: pingBytes,
  387. //}
  388. // 等待响应
  389. if err := waitPongResponse(cab.responseChannels.pongResChannel, 10); err != nil {
  390. return err
  391. }
  392. return nil
  393. }
  394. func waitPongResponse(resChan chan []byte, waitSecond int) error {
  395. ticker := time.NewTicker(time.Second * time.Duration(waitSecond))
  396. for {
  397. select {
  398. case <-ticker.C:
  399. return fmt.Errorf("wait pong time out")
  400. case pongBytes := <-resChan:
  401. if strings.ToUpper(hex.EncodeToString(pongBytes)) == dataProto.PongHex {
  402. return nil
  403. }
  404. }
  405. }
  406. }
  407. func waitCabinetConfigResponse(resChan chan *dataProto.CabinetConfigProto, number uint16, waitSecond int) error {
  408. ticker := time.NewTicker(time.Second * time.Duration(waitSecond))
  409. for {
  410. select {
  411. case <-ticker.C:
  412. return fmt.Errorf("wait CabinetConfig response time out")
  413. case resProto := <-resChan:
  414. log.Info("waitResponse", zap.Any("resProto", resProto))
  415. if resProto.CabinetNumber == number {
  416. return nil
  417. } else {
  418. log.Warnf("set number is %d,but response number is %d,not matched", number, resProto.CabinetNumber)
  419. continue
  420. }
  421. }
  422. }
  423. }
  424. func waitDoorControlResponse(resChan chan *dataProto.DoorControlProto, cmd uint8, waitSecond int) error {
  425. ticker := time.NewTicker(time.Second * time.Duration(waitSecond))
  426. for {
  427. select {
  428. case <-ticker.C:
  429. return fmt.Errorf("wait DoorControl response time out")
  430. case resProto := <-resChan:
  431. log.Info("doorControlResChannel out")
  432. if resProto.Cmd == cmd {
  433. return nil
  434. } else {
  435. log.Warnf("set cmd %d,but response cmd is %d,not matched", cmd, resProto.Cmd)
  436. continue
  437. }
  438. }
  439. }
  440. }
  441. func waitGridControlResponse(resChan chan *dataProto.GridControlProto, cmd uint8, waitSecond int) error {
  442. ticker := time.NewTicker(time.Second * time.Duration(waitSecond))
  443. for {
  444. select {
  445. case <-ticker.C:
  446. return fmt.Errorf("waitGridControlResponse wait response time out")
  447. case resProto := <-resChan:
  448. if resProto == nil {
  449. return fmt.Errorf("res proto is nil")
  450. }
  451. log.Info("gridControlResChannel out")
  452. if resProto.Cmd == cmd {
  453. return nil
  454. } else {
  455. log.Warnf("set cmd %d,but response cmd is %d,not matched", cmd, resProto.Cmd)
  456. continue
  457. }
  458. }
  459. }
  460. }
  461. func waitOpenDoorResponse(resChan chan *dataProto.GridLockStatusProto, cabinetNum uint16, gridNum uint16, waitSecond int) error {
  462. ticker := time.NewTicker(time.Second * time.Duration(waitSecond))
  463. for {
  464. select {
  465. case <-ticker.C:
  466. return fmt.Errorf("wait response time out")
  467. case resProto := <-resChan:
  468. log.Info("waitResponse", zap.Any("resProto", resProto))
  469. if resProto.CabinetNumber != cabinetNum {
  470. return fmt.Errorf("set cabinet number is %d,but response number is %d,not matched", cabinetNum, resProto.CabinetNumber)
  471. }
  472. if resProto.GridNumber != gridNum {
  473. return fmt.Errorf("set gird number is %d,but response number is %d,not matched", gridNum, resProto.GridNumber)
  474. }
  475. if resProto.LockStatus == dataProto.OpenGridLockBroken {
  476. return fmt.Errorf("开启失败,锁故障")
  477. }
  478. if resProto.LockStatus == dataProto.OpenGridLockOpen {
  479. return nil
  480. }
  481. }
  482. }
  483. }
  484. func sendCabinetNum(cabinetId int) error {
  485. err := SetCabinetNumber(cabinetId)
  486. if err != nil {
  487. return err
  488. }
  489. return nil
  490. }
  491. func sendCabinetDoorControl(cabinetId int) error {
  492. cab, ok := cabinets.getCabinet(cabinetId)
  493. if !ok {
  494. return fmt.Errorf("sendCabinetNum err,remoteId %d not found", cabinetId)
  495. }
  496. if cab.memInfo.IsAllowOpen {
  497. if err := EnableOpenDoor(cabinetId, true); err != nil {
  498. return err
  499. }
  500. } else {
  501. if err := DisableOpenDoor(cabinetId); err != nil {
  502. return err
  503. }
  504. }
  505. return nil
  506. }
  507. func sendGetCabinetStatus(cabinetId int) error {
  508. return GetCabinetStatus(cabinetId)
  509. }
  510. func sendVacation(cabinetId int) error {
  511. cab, ok := cabinets.getCabinet(cabinetId)
  512. if !ok {
  513. return fmt.Errorf("sendCabinetNum err,remoteId %d not found", cabinetId)
  514. }
  515. // 获取当前柜子的所有请假人员
  516. var staffs []model.Staff
  517. err := global.DB.Model(&model.Staff{}).Where("cabinet_id = ?", cab.memInfo.CabinetID).Where("vacation_state = ?", 2).Find(&staffs).Error
  518. if err != nil {
  519. return err
  520. }
  521. for _, staff := range staffs {
  522. // 下发请假指令
  523. err = EnableGrid(cabinetId, uint16(staff.GridDeviceID))
  524. if err != nil {
  525. return err
  526. }
  527. // 每个人间隔1毫秒 张总要求
  528. time.Sleep(time.Microsecond)
  529. }
  530. return nil
  531. }