瀏覽代碼

Merge branch 'dev' into dev-web

贾小兵 5 月之前
父節點
當前提交
53035f6b51
共有 44 個文件被更改,包括 2292 次插入760 次删除
  1. 70 69
      pla-sim/01_SQL/02_table/sim_fault.sql
  2. 13 12
      pla-sim/01_SQL/02_table/sim_real_exam_collection.sql
  3. 29 27
      pla-sim/01_SQL/02_table/sim_sim.sql
  4. 394 249
      pla-sim/01_SQL/03_dev_backup/pla-chem-sim-dev-1.sql
  5. 1 1
      ruoyi-admin/src/main/resources/application.yml
  6. 29 0
      ruoyi-sim/src/main/java/com/ruoyi/sim/config/AsyncCommThreadPoolConfig.java
  7. 29 0
      ruoyi-sim/src/main/java/com/ruoyi/sim/config/AsyncLogThreadPoolConfig.java
  8. 63 59
      ruoyi-sim/src/main/java/com/ruoyi/sim/controller/RealExamCollectionController.java
  9. 84 0
      ruoyi-sim/src/main/java/com/ruoyi/sim/controller/TestIotController.java
  10. 29 10
      ruoyi-sim/src/main/java/com/ruoyi/sim/domain/Fault.java
  11. 18 1
      ruoyi-sim/src/main/java/com/ruoyi/sim/domain/RealExam.java
  12. 43 11
      ruoyi-sim/src/main/java/com/ruoyi/sim/domain/RealExamCollection.java
  13. 17 2
      ruoyi-sim/src/main/java/com/ruoyi/sim/domain/RealExamFault.java
  14. 42 16
      ruoyi-sim/src/main/java/com/ruoyi/sim/domain/Sim.java
  15. 18 0
      ruoyi-sim/src/main/java/com/ruoyi/sim/domain/vo/CurrentComp.java
  16. 33 0
      ruoyi-sim/src/main/java/com/ruoyi/sim/domain/vo/CurrentRealExam.java
  17. 16 0
      ruoyi-sim/src/main/java/com/ruoyi/sim/domain/vo/CurrentRealExamCollection.java
  18. 19 0
      ruoyi-sim/src/main/java/com/ruoyi/sim/domain/vo/RealExamCollectionVo.java
  19. 18 0
      ruoyi-sim/src/main/java/com/ruoyi/sim/domain/vo/StudentRealExamIngVo.java
  20. 4 0
      ruoyi-sim/src/main/java/com/ruoyi/sim/domain/vo/StudentRealExamPostVo.java
  21. 87 0
      ruoyi-sim/src/main/java/com/ruoyi/sim/domain/vo/StudentRealExamPreVo.java
  22. 12 0
      ruoyi-sim/src/main/java/com/ruoyi/sim/domain/vo/StudentRealExamVo.java
  23. 109 0
      ruoyi-sim/src/main/java/com/ruoyi/sim/service/impl/CommReceiveService.java
  24. 530 0
      ruoyi-sim/src/main/java/com/ruoyi/sim/service/impl/CommSendService.java
  25. 22 0
      ruoyi-sim/src/main/java/com/ruoyi/sim/service/impl/FaultService.java
  26. 0 276
      ruoyi-sim/src/main/java/com/ruoyi/sim/service/impl/IotService.java
  27. 212 1
      ruoyi-sim/src/main/java/com/ruoyi/sim/service/impl/RealExamCollectionService.java
  28. 86 0
      ruoyi-sim/src/main/java/com/ruoyi/sim/service/impl/RealExamFaultService.java
  29. 171 1
      ruoyi-sim/src/main/java/com/ruoyi/sim/service/impl/RealExamService.java
  30. 0 20
      ruoyi-sim/src/main/java/com/ruoyi/sim/service/impl/SimReceiveService.java
  31. 31 0
      ruoyi-sim/src/main/java/com/ruoyi/sim/service/impl/SimService.java
  32. 3 4
      ruoyi-sim/src/main/java/com/ruoyi/sim/service/impl/TaskService.java
  33. 9 0
      ruoyi-sim/src/main/resources/mapper/sim/FaultMapper.xml
  34. 3 0
      ruoyi-sim/src/main/resources/mapper/sim/MajorMapper.xml
  35. 3 0
      ruoyi-sim/src/main/resources/mapper/sim/RealExamCollectionDeptMapper.xml
  36. 11 0
      ruoyi-sim/src/main/resources/mapper/sim/RealExamCollectionMapper.xml
  37. 3 0
      ruoyi-sim/src/main/resources/mapper/sim/RealExamCompRequestMapper.xml
  38. 3 0
      ruoyi-sim/src/main/resources/mapper/sim/RealExamFaultMapper.xml
  39. 3 0
      ruoyi-sim/src/main/resources/mapper/sim/RealExamMapper.xml
  40. 3 0
      ruoyi-sim/src/main/resources/mapper/sim/SeatMapper.xml
  41. 15 0
      ruoyi-sim/src/main/resources/mapper/sim/SimMapper.xml
  42. 3 0
      ruoyi-sim/src/main/resources/mapper/sim/SimMsg.xml
  43. 3 0
      ruoyi-sim/src/main/resources/mapper/sim/TaskFaultMapper.xml
  44. 1 1
      ruoyi-sim/src/main/resources/mapper/sim/TaskMapper.xml

+ 70 - 69
pla-sim/01_SQL/02_table/sim_fault.sql

@@ -1,17 +1,17 @@
 /*
  Navicat Premium Dump SQL
 
- Source Server         : qdhome.iot321.top-dev
+ Source Server         : 47.104.188.84-sim
  Source Server Type    : MySQL
- Source Server Version : 50740 (5.7.40-log)
- Source Host           : qdhome.iot321.top:33103
+ Source Server Version : 80020 (8.0.20)
+ Source Host           : 47.104.188.84:65006
  Source Schema         : pla-chem-sim-dev-1
 
  Target Server Type    : MySQL
- Target Server Version : 50740 (5.7.40-log)
+ Target Server Version : 80020 (8.0.20)
  File Encoding         : 65001
 
- Date: 18/12/2024 21:39:39
+ Date: 19/12/2024 22:08:21
 */
 
 SET NAMES utf8mb4;
@@ -24,14 +24,15 @@ DROP TABLE IF EXISTS `sim_fault`;
 CREATE TABLE `sim_fault`  (
   `fault_id` char(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '故障ID',
   `parent_fault_id` char(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '父故障ID',
-  `sim_type` char(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '模拟器类型\r\n',
+  `sim_type` char(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '模拟器类型',
   `fault_type` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '故障类型:\r\n1:故障现象\r\n2:故障现象的可能原因\r\n3:故障部位\r\n4:故障部位的排除方法\r\n5:修复结论',
+  `fault_state` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '故障状态\r\n0:启用 \r\n5:禁用',
   `conflict_fault_ids` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '互斥所有故障ID逗号分割',
   `replace_part` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '0' COMMENT '是否是更换件 1:是 0:不是',
   `replace_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '更换件名称',
   `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '名称',
   `bind_hardware_msg` char(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '绑定硬件通信报文',
-  `order_num` int(4) NULL DEFAULT 0 COMMENT '显示顺序',
+  `order_num` int NULL DEFAULT 0 COMMENT '显示顺序',
   `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建者',
   `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
   `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新者',
@@ -43,67 +44,67 @@ CREATE TABLE `sim_fault`  (
 -- ----------------------------
 -- Records of sim_fault
 -- ----------------------------
-INSERT INTO `sim_fault` VALUES ('000100010000', '000000000000', '0001', '1', '', '0', '', '开机无响应', '', 1, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000100010001', '000100010000', '0001', '3', '', '1', '电源开关', '1.电源开关', '01', 1, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000100010002', '000100010000', '0001', '3', '', '1', 'DC/DC转换芯片', '2.DC/DC转换芯片', '02', 2, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000100020000', '000000000000', '0001', '1', '', '0', '', '开机后按抽气开关,微电机不工作', '', 2, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000100020003', '000100020000', '0001', '3', '', '1', '微电机', '3.微电机', '03', 3, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000100020004', '000100020000', '0001', '3', '', '1', 'Q2', '4.Q2', '04', 4, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000100030000', '000000000000', '0001', '1', '', '0', '', '抽气流量不足', '', 3, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000100030005', '000100030000', '0001', '3', '', '1', '滤网', '5.滤网', '05', 5, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000100030006', '000100030000', '0001', '3', '', '1', '调速电位器', '6.调速电位器', '06', 6, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000100040000', '000000000000', '0001', '1', '', '0', '', '开机后按下加热开关,加热灯不亮,也未加热', '', 4, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000100040007', '000100040000', '0001', '3', '', '1', '加热指示灯', '7.加热指示灯', '07', 7, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000100040008', '000100040000', '0001', '3', '', '1', '热敏开关', '8.热敏开关', '08', 8, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000100050000', '000000000000', '0001', '1', '', '0', '', '不能正常工作', '', 5, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000100050009', '000100050000', '0001', '3', '', '1', '外壳及零件', '9.外壳及零件', '09', 9, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000100060000', '000000000000', '0001', '1', '', '0', '', '电压低', '', 6, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000100060010', '000100060000', '0001', '3', '', '1', '供电模块', '10.供电模块', '0A', 10, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000200010000', '000000000000', '0002', '1', '', '0', '', '仪器无法开机', '', 1, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000200010001', '000200010000', '0002', '3', '', '1', '', '1.薄膜开关FPC排线', '', 1, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000200010002', '000200010000', '0002', '3', '', '1', '', '2.主控板开机电路', '', 2, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000200020000', '000000000000', '0002', '1', '', '0', '', '蜂鸣器自检时,声音异常', '', 2, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000200020003', '000200020000', '0002', '3', '', '0', '', '3.蜂鸣器出声口', '', 3, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000200020004', '000200020000', '0002', '3', '', '0', '', '4.接口接线板', '', 4, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000200030000', '000000000000', '0002', '1', '', '0', '', '仪器进入检测界面后,通入检测剂不报警', '', 3, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000200030005', '000200030000', '0002', '3', '', '0', '', '5.检测剂', '', 5, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000200030006', '000200030000', '0002', '3', '', '0', '', '6.主控板信号采集电路', '', 6, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000200040000', '000000000000', '0002', '1', '', '0', '', '显示屏无显示', '', 4, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000200040007', '000200040000', '0002', '3', '', '0', '', '7.主控板显示屏供电电路', '', 7, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000200040008', '000200040000', '0002', '3', '', '0', '', '8.显示屏', '', 8, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000200050000', '000000000000', '0002', '1', '', '0', '', '长时间不进入“检测中”', '', 5, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000200050009', '000200050000', '0002', '3', '', '0', '', '9.干燥管', '', 9, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000200050010', '000200050000', '0002', '3', '', '0', '', '10.维护管', '', 10, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000200060000', '000000000000', '0002', '1', '', '0', '', '不能正常工作', '', 6, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000200060011', '000200060000', '0002', '3', '', '0', '', '11.外壳及零件', '', 11, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000200070000', '000000000000', '0002', '1', '', '0', '', '电压低', '', 7, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000200070012', '000200070000', '0002', '3', '', '0', '', '12.供电模块', '', 12, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000200080000', '000000000000', '0002', '1', '', '0', '', '无法开机', '', 8, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000200080001', '000200080000', '0002', '3', '', '0', '', '13.DC/DC', '', 13, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000300010000', '000000000000', '0003', '1', '', '0', '', '仪器无法开机', '', 1, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000300010001', '000300010000', '0003', '3', '', '0', '', '1.FFC排线', '', 1, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000300010002', '000300010000', '0003', '3', '', '0', '', '2.汇总主控板', '', 2, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000300020000', '000000000000', '0003', '1', '', '0', '', '开机后,显示屏无显示', '', 2, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000300020003', '000300020000', '0003', '3', '', '0', '', '3.显控报警板', '', 3, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000300020004', '000300020000', '0003', '3', '', '0', '', '4.显示屏', '', 4, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000300030000', '000000000000', '0003', '1', '', '0', '', '检测状态下模拟剂不报警', '', 3, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000300030005', '000300030000', '0003', '3', '', '0', '', '5.汇总主控板信号采集电路', '', 5, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000300030006', '000300030000', '0003', '3', '', '0', '', '6.检测剂', '', 6, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000300040000', '000000000000', '0003', '1', '', '0', '', '长时间不能进入检测状态', '', 4, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000300040007', '000300040000', '0003', '3', '', '0', '', '7.干燥管', '', 7, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000300040008', '000300040000', '0003', '3', '', '0', '', '8.维护管', '', 8, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000300050000', '000000000000', '0003', '1', '', '0', '', '固液检测/气体检测模式切换失败', '', 5, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000300050009', '000300050000', '0003', '3', '', '0', '', '9.固液检测单元与主控板连接线', '', 9, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000300050010', '000300050000', '0003', '3', '', '0', '', '10.汇总主控板固液通信电路', '', 10, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000300050011', '000300050000', '0003', '3', '', '0', '', '11.切换按键', '', 11, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000300060000', '000000000000', '0003', '1', '', '0', '', '有毒有害气体检测模块不报警', '', 6, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000300060012', '000300060000', '0003', '3', '', '0', '', '12.高压驱动板与汇总主控板连接线', '', 12, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000300060013', '000300060000', '0003', '3', '', '0', '', '13.汇总主控板毒害模块通信电路', '', 13, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000300070000', '000000000000', '0003', '1', '', '0', '', '不能正常工作', '', 7, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000300070014', '000300070000', '0003', '3', '', '0', '', '14.外壳及零件', '', 14, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000300080000', '000000000000', '0003', '1', '', '0', '', '电压低', '', 8, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000300080015', '000300080000', '0003', '3', '', '0', '', '15.供电模块', '', 15, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000300090000', '000000000000', '0003', '1', '', '0', '', '无法开机', '', 9, NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_fault` VALUES ('000300090016', '000300090000', '0003', '3', '', '0', '', '16.DC/DC', '', 16, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000100010000', '000000000000', '0001', '1', '0', '', '0', '', '开机无响应', '', 1, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000100010001', '000100010000', '0001', '3', '0', '', '1', '电源开关', '1.电源开关', '01', 1, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000100010002', '000100010000', '0001', '3', '0', '', '1', 'DC/DC转换芯片', '2.DC/DC转换芯片', '02', 2, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000100020000', '000000000000', '0001', '1', '0', '', '0', '', '开机后按抽气开关,微电机不工作', '', 2, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000100020003', '000100020000', '0001', '3', '0', '', '1', '微电机', '3.微电机', '03', 3, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000100020004', '000100020000', '0001', '3', '0', '', '1', 'Q2', '4.Q2', '04', 4, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000100030000', '000000000000', '0001', '1', '0', '', '0', '', '抽气流量不足', '', 3, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000100030005', '000100030000', '0001', '3', '0', '', '1', '滤网', '5.滤网', '05', 5, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000100030006', '000100030000', '0001', '3', '0', '', '1', '调速电位器', '6.调速电位器', '06', 6, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000100040000', '000000000000', '0001', '1', '0', '', '0', '', '开机后按下加热开关,加热灯不亮,也未加热', '', 4, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000100040007', '000100040000', '0001', '3', '5', '', '1', '加热指示灯', '7.加热指示灯', '07', 7, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000100040008', '000100040000', '0001', '3', '5', '', '1', '热敏开关', '8.热敏开关', '08', 8, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000100050000', '000000000000', '0001', '1', '0', '', '0', '', '不能正常工作', '', 5, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000100050009', '000100050000', '0001', '3', '5', '', '1', '外壳及零件', '9.外壳及零件', '09', 9, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000100060000', '000000000000', '0001', '1', '0', '', '0', '', '电压低', '', 6, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000100060010', '000100060000', '0001', '3', '5', '', '1', '供电模块', '10.供电模块', '0A', 10, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000200010000', '000000000000', '0002', '1', NULL, '', '0', '', '仪器无法开机', '', 1, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000200010001', '000200010000', '0002', '3', NULL, '', '1', '', '1.薄膜开关FPC排线', '', 1, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000200010002', '000200010000', '0002', '3', NULL, '', '1', '', '2.主控板开机电路', '', 2, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000200020000', '000000000000', '0002', '1', NULL, '', '0', '', '蜂鸣器自检时,声音异常', '', 2, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000200020003', '000200020000', '0002', '3', NULL, '', '0', '', '3.蜂鸣器出声口', '', 3, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000200020004', '000200020000', '0002', '3', NULL, '', '0', '', '4.接口接线板', '', 4, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000200030000', '000000000000', '0002', '1', NULL, '', '0', '', '仪器进入检测界面后,通入检测剂不报警', '', 3, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000200030005', '000200030000', '0002', '3', NULL, '', '0', '', '5.检测剂', '', 5, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000200030006', '000200030000', '0002', '3', NULL, '', '0', '', '6.主控板信号采集电路', '', 6, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000200040000', '000000000000', '0002', '1', NULL, '', '0', '', '显示屏无显示', '', 4, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000200040007', '000200040000', '0002', '3', NULL, '', '0', '', '7.主控板显示屏供电电路', '', 7, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000200040008', '000200040000', '0002', '3', NULL, '', '0', '', '8.显示屏', '', 8, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000200050000', '000000000000', '0002', '1', NULL, '', '0', '', '长时间不进入“检测中”', '', 5, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000200050009', '000200050000', '0002', '3', NULL, '', '0', '', '9.干燥管', '', 9, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000200050010', '000200050000', '0002', '3', NULL, '', '0', '', '10.维护管', '', 10, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000200060000', '000000000000', '0002', '1', NULL, '', '0', '', '不能正常工作', '', 6, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000200060011', '000200060000', '0002', '3', NULL, '', '0', '', '11.外壳及零件', '', 11, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000200070000', '000000000000', '0002', '1', NULL, '', '0', '', '电压低', '', 7, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000200070012', '000200070000', '0002', '3', NULL, '', '0', '', '12.供电模块', '', 12, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000200080000', '000000000000', '0002', '1', NULL, '', '0', '', '无法开机', '', 8, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000200080001', '000200080000', '0002', '3', NULL, '', '0', '', '13.DC/DC', '', 13, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000300010000', '000000000000', '0003', '1', NULL, '', '0', '', '仪器无法开机', '', 1, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000300010001', '000300010000', '0003', '3', NULL, '', '0', '', '1.FFC排线', '', 1, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000300010002', '000300010000', '0003', '3', NULL, '', '0', '', '2.汇总主控板', '', 2, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000300020000', '000000000000', '0003', '1', NULL, '', '0', '', '开机后,显示屏无显示', '', 2, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000300020003', '000300020000', '0003', '3', NULL, '', '0', '', '3.显控报警板', '', 3, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000300020004', '000300020000', '0003', '3', NULL, '', '0', '', '4.显示屏', '', 4, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000300030000', '000000000000', '0003', '1', NULL, '', '0', '', '检测状态下模拟剂不报警', '', 3, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000300030005', '000300030000', '0003', '3', NULL, '', '0', '', '5.汇总主控板信号采集电路', '', 5, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000300030006', '000300030000', '0003', '3', NULL, '', '0', '', '6.检测剂', '', 6, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000300040000', '000000000000', '0003', '1', NULL, '', '0', '', '长时间不能进入检测状态', '', 4, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000300040007', '000300040000', '0003', '3', NULL, '', '0', '', '7.干燥管', '', 7, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000300040008', '000300040000', '0003', '3', NULL, '', '0', '', '8.维护管', '', 8, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000300050000', '000000000000', '0003', '1', NULL, '', '0', '', '固液检测/气体检测模式切换失败', '', 5, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000300050009', '000300050000', '0003', '3', NULL, '', '0', '', '9.固液检测单元与主控板连接线', '', 9, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000300050010', '000300050000', '0003', '3', NULL, '', '0', '', '10.汇总主控板固液通信电路', '', 10, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000300050011', '000300050000', '0003', '3', NULL, '', '0', '', '11.切换按键', '', 11, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000300060000', '000000000000', '0003', '1', NULL, '', '0', '', '有毒有害气体检测模块不报警', '', 6, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000300060012', '000300060000', '0003', '3', NULL, '', '0', '', '12.高压驱动板与汇总主控板连接线', '', 12, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000300060013', '000300060000', '0003', '3', NULL, '', '0', '', '13.汇总主控板毒害模块通信电路', '', 13, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000300070000', '000000000000', '0003', '1', NULL, '', '0', '', '不能正常工作', '', 7, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000300070014', '000300070000', '0003', '3', NULL, '', '0', '', '14.外壳及零件', '', 14, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000300080000', '000000000000', '0003', '1', NULL, '', '0', '', '电压低', '', 8, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000300080015', '000300080000', '0003', '3', NULL, '', '0', '', '15.供电模块', '', 15, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000300090000', '000000000000', '0003', '1', NULL, '', '0', '', '无法开机', '', 9, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_fault` VALUES ('000300090016', '000300090000', '0003', '3', NULL, '', '0', '', '16.DC/DC', '', 16, NULL, NULL, NULL, NULL, NULL);
 
 SET FOREIGN_KEY_CHECKS = 1;

+ 13 - 12
pla-sim/01_SQL/02_table/sim_real_exam_collection.sql

@@ -1,17 +1,17 @@
 /*
  Navicat Premium Dump SQL
 
- Source Server         : qdhome.iot321.top-dev
+ Source Server         : 47.104.188.84-sim
  Source Server Type    : MySQL
- Source Server Version : 50740 (5.7.40-log)
- Source Host           : qdhome.iot321.top:33103
+ Source Server Version : 80020 (8.0.20)
+ Source Host           : 47.104.188.84:65006
  Source Schema         : pla-chem-sim-dev-1
 
  Target Server Type    : MySQL
- Target Server Version : 50740 (5.7.40-log)
+ Target Server Version : 80020 (8.0.20)
  File Encoding         : 65001
 
- Date: 15/12/2024 19:22:55
+ Date: 23/12/2024 11:50:02
 */
 
 SET NAMES utf8mb4;
@@ -22,22 +22,23 @@ SET FOREIGN_KEY_CHECKS = 0;
 -- ----------------------------
 DROP TABLE IF EXISTS `sim_real_exam_collection`;
 CREATE TABLE `sim_real_exam_collection`  (
-  `exam_collection_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '考试集合ID',
+  `exam_collection_id` bigint NOT NULL AUTO_INCREMENT COMMENT '考试集合ID',
   `sim_type` char(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '模拟器类型',
-  `question_setting_method` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '出题方式:\r\n1 系统随机\r\n2 教师自选\r\n3 任务自选\r\n',
-  `exam_collection_type` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '考试类型\r\n1:练习\r\n2:自主练习\r\n3:考试',
+  `question_setting_method` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '出题方式:[1]-系统随机,[2]-教师自选,[3]任务自选\r\n',
+  `exam_collection_type` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '考试类型:[1]-练习,[2]-自主练习,[3]-考试',
+  `exam_collection_state` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '考试集合状态:[0]-初始化,[2]-打开,[3]-关闭',
   `exam_collection_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '考试名称',
-  `task_id` bigint(20) NULL DEFAULT 0 COMMENT '任务ID',
-  `limit_duration` int(6) NULL DEFAULT NULL COMMENT '限制时长(分钟)',
+  `task_id` bigint NULL DEFAULT 0 COMMENT '任务ID',
+  `limit_duration` int NULL DEFAULT NULL COMMENT '限制时长(分钟)',
   `start_time` datetime NULL DEFAULT NULL COMMENT '考试开始时间(天)',
   `end_time` datetime NULL DEFAULT NULL COMMENT '考试结束时间(天)',
-  `create_user_id` bigint(20) NULL DEFAULT 0 COMMENT '创建教师ID/用户ID',
+  `create_user_id` bigint NULL DEFAULT 0 COMMENT '创建教师ID/用户ID',
   `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建者',
   `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
   `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新者',
   `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
   `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
   PRIMARY KEY (`exam_collection_id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'sim-考试集合表' ROW_FORMAT = DYNAMIC;
+) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'sim-考试集合表' ROW_FORMAT = DYNAMIC;
 
 SET FOREIGN_KEY_CHECKS = 1;

+ 29 - 27
pla-sim/01_SQL/02_table/sim_sim.sql

@@ -1,17 +1,17 @@
 /*
  Navicat Premium Dump SQL
 
- Source Server         : qdhome.iot321.top-dev
+ Source Server         : 47.104.188.84-sim
  Source Server Type    : MySQL
- Source Server Version : 50740 (5.7.40-log)
- Source Host           : qdhome.iot321.top:33103
+ Source Server Version : 80020 (8.0.20)
+ Source Host           : 47.104.188.84:65006
  Source Schema         : pla-chem-sim-dev-1
 
  Target Server Type    : MySQL
- Target Server Version : 50740 (5.7.40-log)
+ Target Server Version : 80020 (8.0.20)
  File Encoding         : 65001
 
- Date: 18/12/2024 21:16:24
+ Date: 19/12/2024 22:07:24
 */
 
 SET NAMES utf8mb4;
@@ -22,12 +22,14 @@ SET FOREIGN_KEY_CHECKS = 0;
 -- ----------------------------
 DROP TABLE IF EXISTS `sim_sim`;
 CREATE TABLE `sim_sim`  (
-  `sim_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '模拟器ID',
-  `seat_id` bigint(20) NOT NULL COMMENT '座ID',
+  `sim_id` bigint NOT NULL AUTO_INCREMENT COMMENT '模拟器ID',
+  `seat_id` bigint NOT NULL COMMENT '座ID',
   `sim_type` char(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '模拟器类型',
   `sim_state` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '0' COMMENT '模拟器状态 0:可用初始化 1:在线 2:模拟器离线 3:网关离线 4:硬件故障异常 5:手动禁用',
   `sim_sn` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '模拟器序列号',
   `sim_num` char(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '模拟器设备编号1~30',
+  `last_sent_time` datetime NULL DEFAULT NULL COMMENT '最后一次成功发送报文时间',
+  `last_received_time` datetime NULL DEFAULT NULL COMMENT '最后一次成功收到报文时间',
   `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建者',
   `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
   `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新者',
@@ -39,25 +41,25 @@ CREATE TABLE `sim_sim`  (
 -- ----------------------------
 -- Records of sim_sim
 -- ----------------------------
-INSERT INTO `sim_sim` VALUES (11, 1, '0001', '0', '01123456', '1', NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_sim` VALUES (12, 2, '0001', '5', 'A0002', '2', NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_sim` VALUES (13, 3, '0001', '5', 'A0003', '3', NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_sim` VALUES (14, 4, '0001', '5', 'A0004', '4', NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_sim` VALUES (15, 5, '0001', '5', 'A0005', '5', NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_sim` VALUES (16, 6, '0001', '5', 'A0006', '6', NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_sim` VALUES (17, 7, '0001', '5', 'A0007', '7', NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_sim` VALUES (18, 8, '0001', '5', 'A0008', '8', NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_sim` VALUES (19, 9, '0001', '5', 'A0009', '9', NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_sim` VALUES (20, 10, '0001', '5', 'A0010', '10', NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_sim` VALUES (21, 1, '0002', '5', 'B0001', '11', NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_sim` VALUES (22, 2, '0002', '5', 'B0002', '12', NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_sim` VALUES (23, 3, '0002', '5', 'B0003', '13', NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_sim` VALUES (24, 4, '0002', '5', 'B0004', '14', NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_sim` VALUES (25, 5, '0002', '5', 'B0005', '15', NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_sim` VALUES (26, 6, '0002', '5', 'B0006', '16', NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_sim` VALUES (27, 7, '0002', '5', 'B0006', '17', NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_sim` VALUES (28, 8, '0002', '5', 'B0007', '18', NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_sim` VALUES (29, 9, '0002', '5', 'B0008', '19', NULL, NULL, NULL, NULL, NULL);
-INSERT INTO `sim_sim` VALUES (30, 10, '0002', '5', 'B0008', '20', NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_sim` VALUES (11, 1, '0001', '1', '01010101', '01', '2024-12-19 22:02:16', '2024-12-19 22:02:18', NULL, '2024-12-19 17:32:47', NULL, '2024-12-19 21:06:32', NULL);
+INSERT INTO `sim_sim` VALUES (12, 2, '0001', '5', 'A0002', '02', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_sim` VALUES (13, 3, '0001', '5', 'A0003', '03', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_sim` VALUES (14, 4, '0001', '5', 'A0004', '04', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_sim` VALUES (15, 5, '0001', '5', 'A0005', '05', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_sim` VALUES (16, 6, '0001', '5', 'A0006', '06', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_sim` VALUES (17, 7, '0001', '5', 'A0007', '07', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_sim` VALUES (18, 8, '0001', '5', 'A0008', '08', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_sim` VALUES (19, 9, '0001', '5', 'A0009', '09', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_sim` VALUES (20, 10, '0001', '5', 'A0010', '10', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_sim` VALUES (21, 1, '0002', '5', 'B0001', '11', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_sim` VALUES (22, 2, '0002', '5', 'B0002', '12', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_sim` VALUES (23, 3, '0002', '5', 'B0003', '13', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_sim` VALUES (24, 4, '0002', '5', 'B0004', '14', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_sim` VALUES (25, 5, '0002', '5', 'B0005', '15', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_sim` VALUES (26, 6, '0002', '5', 'B0006', '16', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_sim` VALUES (27, 7, '0002', '5', 'B0006', '17', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_sim` VALUES (28, 8, '0002', '5', 'B0007', '18', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_sim` VALUES (29, 9, '0002', '5', 'B0008', '19', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO `sim_sim` VALUES (30, 10, '0002', '5', 'B0008', '20', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 
 SET FOREIGN_KEY_CHECKS = 1;

File diff suppressed because it is too large
+ 394 - 249
pla-sim/01_SQL/03_dev_backup/pla-chem-sim-dev-1.sql


+ 1 - 1
ruoyi-admin/src/main/resources/application.yml

@@ -36,7 +36,7 @@ logging:
   level:
     com.ruoyi: debug
     org.springframework: warn
-
+    com.ruoyi.sim: debug
 # 用户配置
 user:
   password:

+ 29 - 0
ruoyi-sim/src/main/java/com/ruoyi/sim/config/AsyncCommThreadPoolConfig.java

@@ -0,0 +1,29 @@
+package com.ruoyi.sim.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * 非核心业务的线程池。
+ */
+@Configuration
+@EnableAsync
+public class AsyncCommThreadPoolConfig {
+
+    @Bean(name = "tp-comm")
+    public ThreadPoolTaskExecutor executor() {
+        ThreadPoolTaskExecutor e = new ThreadPoolTaskExecutor();
+        e.setCorePoolSize(10);
+        e.setMaxPoolSize(100);
+        e.setQueueCapacity(50);
+        e.setKeepAliveSeconds(200);
+        e.setThreadNamePrefix("tp-comm-");
+        e.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
+        e.initialize();
+        return e;
+    }
+}

+ 29 - 0
ruoyi-sim/src/main/java/com/ruoyi/sim/config/AsyncLogThreadPoolConfig.java

@@ -0,0 +1,29 @@
+package com.ruoyi.sim.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * 非核心业务的线程池。
+ */
+@Configuration
+@EnableAsync
+public class AsyncLogThreadPoolConfig {
+
+    @Bean(name = "tp-log")
+    public ThreadPoolTaskExecutor executor() {
+        ThreadPoolTaskExecutor e = new ThreadPoolTaskExecutor();
+        e.setCorePoolSize(10);
+        e.setMaxPoolSize(100);
+        e.setQueueCapacity(50);
+        e.setKeepAliveSeconds(200);
+        e.setThreadNamePrefix("tp-log-");
+        e.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
+        e.initialize();
+        return e;
+    }
+}

+ 63 - 59
ruoyi-sim/src/main/java/com/ruoyi/sim/controller/RealExamCollectionController.java

@@ -1,12 +1,9 @@
 package com.ruoyi.sim.controller;
 
-import java.util.List;
-import javax.servlet.http.HttpServletResponse;
-
+import com.ruoyi.sim.domain.vo.RealExamCollectionVo;
 import com.ruoyi.sim.service.impl.RealExamCollectionService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
-import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -21,8 +18,6 @@ import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.enums.BusinessType;
 import com.ruoyi.sim.domain.RealExamCollection;
-import com.ruoyi.common.utils.poi.ExcelUtil;
-import com.ruoyi.common.core.page.TableDataInfo;
 
 /**
  * 考试集合Controller
@@ -34,70 +29,79 @@ import com.ruoyi.common.core.page.TableDataInfo;
 @RequestMapping("/sim/real-exam-collection")
 @Api("考试集合Controller")
 public class RealExamCollectionController extends BaseController {
+
     @Autowired
-    private RealExamCollectionService realExamCollectionService;
+    private RealExamCollectionService service;
+
+    @GetMapping("/teacher/exam/list")
+    @ApiOperation("[教师][分页]查询考试集合列表")
+    public AjaxResult listExamByTeacher(RealExamCollection p) {
+        return service.listExamByTeacher(p);
+    }
+
+    @GetMapping("/teacher/exercise/list")
+    @ApiOperation("[教师][分页]查询考试集合列表")
+    public AjaxResult listExerciseByTeacher(RealExamCollection p) {
+        return service.listExerciseByTeacher(p);
+    }
+
+    @GetMapping(value = "/teacher/exam/{id}")
+    @ApiOperation("[教师]获取考试集合详细信息")
+    public AjaxResult getExamInfoByTeacher(@PathVariable("id") Long id) {
+        return service.getExamInfoByTeacher(id);
+    }
+
+    @GetMapping(value = "/teacher/exercise/{id}")
+    @ApiOperation("[教师]获取练习集合详细信息")
+    public AjaxResult getExerciseInfoByTeacher(@PathVariable("id") Long id) {
+        return service.getExerciseInfoByTeacher(id);
+    }
+
+    @PostMapping(value = "/teacher/exam/")
+    @ApiOperation("[教师]新增考试集合")
+    public AjaxResult addExam(@RequestBody RealExamCollectionVo vo) {
+        return service.addExam(vo);
+    }
+
+    @PostMapping(value = "/teacher/exercise/")
+    @ApiOperation("[教师]新增练习集合")
+    public AjaxResult addExercise(@RequestBody RealExamCollectionVo vo) {
+        return service.addExercise(vo);
+    }
 
-    // @PreAuthorize("@ss.hasPermi('sim:real-exam-collection:list')")
-    @GetMapping("/list")
-    @ApiOperation("[老师]查询考试集合列表")
-    public TableDataInfo list(RealExamCollection realExamCollection) {
-        startPage();
-        List<RealExamCollection> list = realExamCollectionService.selectRealExamCollectionList(realExamCollection);
-        return getDataTable(list);
+    @PutMapping(value = "/teacher/exam/")
+    @ApiOperation("[教师]修改考试集合")
+    public AjaxResult editExam(@RequestBody RealExamCollectionVo vo) {
+        return service.editExam(vo);
     }
 
-    /**
-     * 导出考试集合列表
-     */
-    @PreAuthorize("@ss.hasPermi('sim:real-exam-collection:export')")
-    @Log(title = "考试集合", businessType = BusinessType.EXPORT)
-    @PostMapping("/export")
-    public void export(HttpServletResponse response, RealExamCollection realExamCollection) {
-        List<RealExamCollection> list = realExamCollectionService.selectRealExamCollectionList(realExamCollection);
-        ExcelUtil<RealExamCollection> util = new ExcelUtil<RealExamCollection>(RealExamCollection.class);
-        util.exportExcel(response, list, "考试集合数据");
+    @PutMapping(value = "/teacher/exercise/")
+    @ApiOperation("[教师]修改练习集合")
+    public AjaxResult edit(@RequestBody RealExamCollectionVo vo) {
+        return service.editExercise(vo);
     }
 
-    /**
-     * 获取考试集合详细信息
-     */
-    // @PreAuthorize("@ss.hasPermi('sim:real-exam-collection:query')")
-    @GetMapping(value = "/{examCollectionId}")
-    @ApiOperation("[老师]获取考试集合详细信息")
-    public AjaxResult getInfo(@PathVariable("examCollectionId") Long examCollectionId) {
-        return success(realExamCollectionService.selectRealExamCollectionByExamCollectionId(examCollectionId));
+    @DeleteMapping("/teacher/exam/{ids}")
+    @ApiOperation("[教师]删除多个考试集合")
+    public AjaxResult deleteExams(@PathVariable Long[] ids) {
+        return service.deleteExams(ids);
     }
 
-    /**
-     * 新增考试集合
-     */
-    @PreAuthorize("@ss.hasPermi('sim:real-exam-collection:add')")
-    @Log(title = "考试集合", businessType = BusinessType.INSERT)
-    @PostMapping
-    @ApiOperation("[老师]新增考试集合")
-    public AjaxResult add(@RequestBody RealExamCollection realExamCollection) {
-        return toAjax(realExamCollectionService.insertRealExamCollection(realExamCollection));
+    @DeleteMapping("/teacher/exercise/{ids}")
+    @ApiOperation("[教师]删除多个考试集合")
+    public AjaxResult deleteExercises(@PathVariable Long[] ids) {
+        return service.deleteExercises(ids);
     }
 
-    /**
-     * 修改考试集合
-     */
-    @PreAuthorize("@ss.hasPermi('sim:real-exam-collection:edit')")
-    @Log(title = "考试集合", businessType = BusinessType.UPDATE)
-    @PutMapping
-    @ApiOperation("[老师]修改考试集合")
-    public AjaxResult edit(@RequestBody RealExamCollection realExamCollection) {
-        return toAjax(realExamCollectionService.updateRealExamCollection(realExamCollection));
+    @PutMapping(value = "/teacher/exam/open/{id}")
+    @ApiOperation("[教师]打开考试集合")
+    public AjaxResult openExam(@PathVariable("id") Long id) {
+        return service.openExam(id);
     }
 
-    /**
-     * 删除考试集合
-     */
-    @PreAuthorize("@ss.hasPermi('sim:real-exam-collection:remove')")
-    @Log(title = "考试集合", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{examCollectionIds}")
-    @ApiOperation("[老师]删除考试集合")
-    public AjaxResult remove(@PathVariable Long[] examCollectionIds) {
-        return toAjax(realExamCollectionService.deleteRealExamCollectionByExamCollectionIds(examCollectionIds));
+    @PutMapping(value = "/teacher/exam/close/{id}")
+    @ApiOperation("[教师]关闭考试集合")
+    public AjaxResult closeExam(@PathVariable("id") Long id) {
+        return service.closeExam(id);
     }
 }

+ 84 - 0
ruoyi-sim/src/main/java/com/ruoyi/sim/controller/TestIotController.java

@@ -0,0 +1,84 @@
+package com.ruoyi.sim.controller;
+
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.sim.domain.RealExam;
+import com.ruoyi.sim.service.impl.CommSendService;
+import com.ruoyi.sim.service.impl.MajorService;
+import com.ruoyi.sim.service.impl.RealExamService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/sim/iot")
+@Api("测试通信Controller")
+public class TestIotController extends BaseController {
+
+    @Autowired
+    private MajorService majorService;
+    @Autowired
+    private CommSendService commSnedService;
+    @Autowired
+    private RealExamService realExamService;
+
+    @ApiOperation("testIot通信")
+    @GetMapping(value = "/{codeId}")
+    public AjaxResult testIndex(@PathVariable("codeId") Integer codeId) {
+        switch (codeId) {
+            case 1: {
+                commSnedService.checkAllSimState();
+            }
+            break;
+            case 2: {
+                // commSnedService.clearOneFault(null, null, null);
+            }
+            break;
+            case 3: {
+                // commSnedService.readOneFaultResistance(null, null);
+            }
+            break;
+            case 4: {
+                // commSnedService.writeOneFault(null, null, null);
+            }
+            break;
+            case 5: {
+//                for (int i = 0; i < 100; i++) {
+//                    commSnedService.readOneFaultResistance(null, null);
+//                }
+            }
+            break;
+            case 6: {
+                RealExam re = realExamService.selectRealExamByExamId(1L);
+                commSnedService.clearListFaultByRealExam(re);
+            }
+            break;
+            case 7: {
+                commSnedService.test();
+            }
+            break;
+            case 10: {
+                commSnedService.checkAllSimState();
+                commSnedService.clearAll();
+                RealExam re = realExamService.selectRealExamByExamId(1L);
+                commSnedService.clearListFaultByRealExam(re);
+            }
+            break;
+            case 11: {
+                commSnedService.readAll();
+            }
+            break;
+            case 12: {
+                RealExam re = realExamService.selectRealExamByExamId(1L);
+                commSnedService.readOneExamAtLast(re);
+                //
+            }
+            break;
+        }
+        return AjaxResult.success();
+    }
+}

+ 29 - 10
ruoyi-sim/src/main/java/com/ruoyi/sim/domain/Fault.java

@@ -26,8 +26,7 @@ public class Fault extends BaseEntity implements Comparable<Fault> {
     @Excel(name = "父故障ID")
     private String parentFaultId;
 
-    /**
-     * 模拟器类型
+    /** 模拟器类型
      */
     @Excel(name = "模拟器类型")
     private String simType;
@@ -44,6 +43,14 @@ public class Fault extends BaseEntity implements Comparable<Fault> {
     private String faultType;
 
     /**
+     * 故障状态
+     * 0:启用
+     * 5:禁用
+     */
+    @Excel(name = "故障状态")
+    private String faultState;
+
+    /**
      * 互斥所有故障ID逗号分割
      */
     @Excel(name = "互斥所有故障ID逗号分割")
@@ -77,7 +84,7 @@ public class Fault extends BaseEntity implements Comparable<Fault> {
      * 显示顺序
      */
     @Excel(name = "显示顺序")
-    private Integer orderNum;
+    private Long orderNum;
 
     public void setFaultId(String faultId) {
         this.faultId = faultId;
@@ -111,6 +118,14 @@ public class Fault extends BaseEntity implements Comparable<Fault> {
         return faultType;
     }
 
+    public void setFaultState(String faultState) {
+        this.faultState = faultState;
+    }
+
+    public String getFaultState() {
+        return faultState;
+    }
+
     public void setConflictFaultIds(String conflictFaultIds) {
         this.conflictFaultIds = conflictFaultIds;
     }
@@ -151,11 +166,11 @@ public class Fault extends BaseEntity implements Comparable<Fault> {
         return bindHardwareMsg;
     }
 
-    public void setOrderNum(Integer orderNum) {
+    public void setOrderNum(Long orderNum) {
         this.orderNum = orderNum;
     }
 
-    public Integer getOrderNum() {
+    public Long getOrderNum() {
         return orderNum;
     }
 
@@ -166,6 +181,7 @@ public class Fault extends BaseEntity implements Comparable<Fault> {
                 .append("parentFaultId", getParentFaultId())
                 .append("simType", getSimType())
                 .append("faultType", getFaultType())
+                .append("faultState", getFaultState())
                 .append("conflictFaultIds", getConflictFaultIds())
                 .append("replacePart", getReplacePart())
                 .append("replaceName", getReplaceName())
@@ -190,11 +206,14 @@ public class Fault extends BaseEntity implements Comparable<Fault> {
         }
     }
 
-    public static String FAULT_TYPE_1 = "1";
-    public static String FAULT_TYPE_2 = "2";
-    public static String FAULT_TYPE_3 = "3";
-    public static String FAULT_TYPE_4 = "4";
-    public static String FAULT_TYPE_5 = "5";
+    public static String TYPE_1 = "1";
+    public static String TYPE_2 = "2";
+    public static String TYPE_3 = "3";
+    public static String TYPE_4 = "4";
+    public static String TYPE_5 = "5";
+
+    public static String STATE_ENABLE = "0";
+    public static String STATE_DISABLE = "1";
 
     public static String ROOT_FAULT_ID = "000000000000";
 }

+ 18 - 1
ruoyi-sim/src/main/java/com/ruoyi/sim/domain/RealExam.java

@@ -15,6 +15,7 @@ import com.ruoyi.common.core.domain.BaseEntity;
  * @date 2024-12-15
  */
 public class RealExam extends BaseEntity {
+
     private static final long serialVersionUID = 1L;
 
     /**
@@ -50,10 +51,11 @@ public class RealExam extends BaseEntity {
      * 考试状态
      * 0:未登录
      * 1:已登录
+     * 2:故障下发中
      * 2:模拟器检查并下发ok
      * 3:答题中
      * 4:已交卷
-     * 5:获取模拟成绩分析
+     * 5:已经获取模拟成绩分析
      * 80:教师标记缺考
      * 81:登录未开始答题
      * 90:模拟器异常结束
@@ -219,4 +221,19 @@ public class RealExam extends BaseEntity {
                 .append("remark", getRemark())
                 .toString();
     }
+
+    // -------------------------------- tom add  --------------------------------
+
+    public static final String STATE_NOT_LOGGED_IN = "0";
+
+    public static final String STATE_LOGGED_IN = "1";
+    public static final String STATE_SIM_WRITING = "2????";// todo:??
+    public static final String STATE_SIM_PREPARE_OK = "2";
+    public static final String STATE_ANSWERING = "3";
+    public static final String STATE_SUBMITTED = "4";
+    public static final String STATE_CALCULATING_SCORE = "4????";// todo:??
+    public static final String STATE_GOT_REPORT = "5";
+    public static final String STATE_ABSENCE_BY_TEACHER = "80";
+    public static final String STATE_LOGIN_NOT_STARTED_ANSWERING_QUESTIONS = "81";
+    public static final String STATE_SIMULATOR_ERROR = "90";
 }

+ 43 - 11
ruoyi-sim/src/main/java/com/ruoyi/sim/domain/RealExamCollection.java

@@ -15,6 +15,7 @@ import com.ruoyi.common.core.domain.BaseEntity;
  * @date 2024-12-17
  */
 public class RealExamCollection extends BaseEntity {
+
     private static final long serialVersionUID = 1L;
 
     /**
@@ -28,18 +29,15 @@ public class RealExamCollection extends BaseEntity {
     @Excel(name = "模拟器类型")
     private String simType;
 
-    /** 出题方式:
-     1 系统随机
-     2 教师自选
-     3 任务自选
+    /**
+     * 出题方式:[1]-系统随机,[2]-教师自选,[3]任务自选
      */
     @Excel(name = "出题方式")
     private String questionSettingMethod;
 
-    /** 考试类型
-     1:练习
-     2:自主练习
-     3:考试 */
+    /**
+     * 考试类型:[1]-练习,[2]-自主练习,[3]-考试
+     */
     @Excel(name = "考试类型")
     private String examCollectionType;
 
@@ -50,6 +48,12 @@ public class RealExamCollection extends BaseEntity {
     private String examCollectionName;
 
     /**
+     * 考试集合状态:[0]-初始化,[2]-打开,[3]-关闭
+     */
+    @Excel(name = "考试集合状态:[0]-初始化,[2]-打开,[3]-关闭")
+    private String examCollectionState;
+
+    /**
      * 任务ID
      */
     @Excel(name = "任务ID")
@@ -59,7 +63,7 @@ public class RealExamCollection extends BaseEntity {
      * 限制时长(分钟)
      */
     @Excel(name = "限制时长(分钟)")
-    private Integer limitDuration;
+    private Long limitDuration;
 
     /**
      * 考试开始时间(天)
@@ -121,6 +125,14 @@ public class RealExamCollection extends BaseEntity {
         return examCollectionName;
     }
 
+    public void setExamCollectionState(String examCollectionState) {
+        this.examCollectionState = examCollectionState;
+    }
+
+    public String getExamCollectionState() {
+        return examCollectionState;
+    }
+
     public void setTaskId(Long taskId) {
         this.taskId = taskId;
     }
@@ -129,11 +141,11 @@ public class RealExamCollection extends BaseEntity {
         return taskId;
     }
 
-    public void setLimitDuration(Integer limitDuration) {
+    public void setLimitDuration(Long limitDuration) {
         this.limitDuration = limitDuration;
     }
 
-    public Integer getLimitDuration() {
+    public Long getLimitDuration() {
         return limitDuration;
     }
 
@@ -169,6 +181,7 @@ public class RealExamCollection extends BaseEntity {
                 .append("questionSettingMethod", getQuestionSettingMethod())
                 .append("examCollectionType", getExamCollectionType())
                 .append("examCollectionName", getExamCollectionName())
+                .append("examCollectionState", getExamCollectionState())
                 .append("taskId", getTaskId())
                 .append("limitDuration", getLimitDuration())
                 .append("startTime", getStartTime())
@@ -181,4 +194,23 @@ public class RealExamCollection extends BaseEntity {
                 .append("remark", getRemark())
                 .toString();
     }
+
+    // -------------------------------- tom add  --------------------------------
+    public interface SettingMethod {
+        String SYSTEM_RANDOM = "1";
+        String TEACHER_SELECT = "2";
+        String TASK_SELECT = "3";
+    }
+
+    public interface Type {
+        String EXERCISE = "1";
+        String SELF_EXERCISE = "2";
+        String EXAM = "3";
+    }
+
+    public interface State {
+        String INIT = "0";
+        String OPENED = "2";
+        String CLOSED = "3";
+    }
 }

+ 17 - 2
ruoyi-sim/src/main/java/com/ruoyi/sim/domain/RealExamFault.java

@@ -12,6 +12,7 @@ import com.ruoyi.common.core.domain.BaseEntity;
  * @date 2024-12-18
  */
 public class RealExamFault extends BaseEntity {
+
     private static final long serialVersionUID = 1L;
 
     /**
@@ -50,8 +51,8 @@ public class RealExamFault extends BaseEntity {
      * 0:初始化
      * 1:已经清除故障
      * 2:故障已经下发
-     * 3:轮读取刷新电阻代表值
-     * 3:考试结束
+     * 3:轮读取刷新电阻代表值
+     * 4:考试结束
      */
     @Excel(name = "故障ID关联状态")
     private String refState;
@@ -195,4 +196,18 @@ public class RealExamFault extends BaseEntity {
                 .append("remark", getRemark())
                 .toString();
     }
+
+    // -------------------------------- tom add  --------------------------------
+    public static final String REF_TYPE_1 = "1";
+    public static final String REF_TYPE_2 = "2";
+
+    public static final String REF_STATE_INIT = "0";
+    public static final String REF_STATE_CLEARED = "1";
+    public static final String REF_STATE_WRITTEN = "2";
+    public static final String REF_STATE_LOOP_READ = "3";
+    public static final String REF_STATE_FINISH = "4";
+
+    public static final String FLAG_YES = "1";
+    public static final String FLAG_NO = "0";
+    public static final String FLAG_UNKNOWN = "7";
 }

+ 42 - 16
ruoyi-sim/src/main/java/com/ruoyi/sim/domain/Sim.java

@@ -1,5 +1,6 @@
 package com.ruoyi.sim.domain;
 
+import com.fasterxml.jackson.annotation.JsonFormat;
 import org.apache.commons.lang3.builder.ToStringBuilder;
 import org.apache.commons.lang3.builder.ToStringStyle;
 import com.ruoyi.common.annotation.Excel;
@@ -52,6 +53,20 @@ public class Sim extends BaseEntity {
     @Excel(name = "模拟器设备编号1~30")
     private String simNum;
 
+    /**
+     * 最后一次成功发送报文时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    // @Excel(name = "最后一次成功发送报文时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date lastSentTime;
+
+    /**
+     * 最后一次成功收到报文时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    // @Excel(name = "最后一次成功收到报文时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date lastReceivedTime;
+
     public void setSimId(Long simId) {
         this.simId = simId;
     }
@@ -100,6 +115,22 @@ public class Sim extends BaseEntity {
         return simNum;
     }
 
+    public void setLastSentTime(Date lastSentTime) {
+        this.lastSentTime = lastSentTime;
+    }
+
+    public Date getLastSentTime() {
+        return lastSentTime;
+    }
+
+    public void setLastReceivedTime(Date lastReceivedTime) {
+        this.lastReceivedTime = lastReceivedTime;
+    }
+
+    public Date getLastReceivedTime() {
+        return lastReceivedTime;
+    }
+
     @Override
     public String toString() {
         return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
@@ -109,6 +140,8 @@ public class Sim extends BaseEntity {
                 .append("simState", getSimState())
                 .append("simSn", getSimSn())
                 .append("simNum", getSimNum())
+                .append("lastSentTime", getLastSentTime())
+                .append("lastReceivedTime", getLastReceivedTime())
                 .append("createBy", getCreateBy())
                 .append("createTime", getCreateTime())
                 .append("updateBy", getUpdateBy())
@@ -131,13 +164,7 @@ public class Sim extends BaseEntity {
      */
     public static final String TYPE_0003 = "0003";
 
-    public static final Set<String> TYPE_SET = new HashSet<>(
-            Arrays.asList(
-                    TYPE_0001,
-                    TYPE_0002,
-                    TYPE_0003
-            )
-    );
+    public static final Set<String> TYPE_SET = new HashSet<>(Arrays.asList(TYPE_0001, TYPE_0002, TYPE_0003));
 
     public static final String TYPE_0001_NAME = "FZD04B";
     public static final String TYPE_0002_NAME = "FZB006";
@@ -156,13 +183,12 @@ public class Sim extends BaseEntity {
     public static String STATE_SIM_ERROR = "4";
     public static String STATE_DISABLE = "5";
 
-    public static final Set<String> STATE_SET = new HashSet<>(
-            Arrays.asList(
-                    STATE_ONLINE,
-                    STATE_SIM_OFFLINE,
-                    STATE_GATEWAY_OFFLINE,
-                    STATE_SIM_ERROR,
-                    STATE_DISABLE
-            )
-    );
+    public static final Set<String> STATE_SET = new HashSet<>(Arrays.asList(
+            STATE_ENABLE_INIT,
+            STATE_ONLINE,
+            STATE_SIM_OFFLINE,
+            STATE_GATEWAY_OFFLINE,
+            STATE_SIM_ERROR,
+            STATE_DISABLE
+    ));
 }

+ 18 - 0
ruoyi-sim/src/main/java/com/ruoyi/sim/domain/vo/CurrentComp.java

@@ -0,0 +1,18 @@
+package com.ruoyi.sim.domain.vo;
+
+import com.ruoyi.sim.domain.RealExamCompRequest;
+import com.ruoyi.sim.domain.Seat;
+import com.ruoyi.sim.domain.Student;
+
+import java.util.List;
+
+public class CurrentComp {
+
+    private Seat seat;
+
+    private List<RealExamCompRequest> requestList;
+
+    private Student student;
+
+
+}

+ 33 - 0
ruoyi-sim/src/main/java/com/ruoyi/sim/domain/vo/CurrentRealExam.java

@@ -0,0 +1,33 @@
+package com.ruoyi.sim.domain.vo;
+
+import com.ruoyi.sim.domain.*;
+
+import java.util.List;
+
+public class CurrentRealExam {
+
+    /**
+     * 座
+     */
+    private Seat seat;
+
+    /**
+     * 模拟器
+     */
+    private Sim sim;
+
+    /**
+     * 学生
+     */
+    private Student student;
+
+    /**
+     * 考试
+     */
+    private RealExam realExam;
+
+    /**
+     * 出题题目
+     */
+    private List<Fault> faultList;
+}

+ 16 - 0
ruoyi-sim/src/main/java/com/ruoyi/sim/domain/vo/CurrentRealExamCollection.java

@@ -0,0 +1,16 @@
+package com.ruoyi.sim.domain.vo;
+
+import com.ruoyi.sim.domain.*;
+
+import java.util.List;
+
+/**
+ * 聚合返回值。
+ */
+public class CurrentRealExamCollection {
+
+    private RealExamCollection realExamCollection;
+
+    private List<CurrentRealExam> ceList;
+
+}

+ 19 - 0
ruoyi-sim/src/main/java/com/ruoyi/sim/domain/vo/RealExamCollectionVo.java

@@ -0,0 +1,19 @@
+package com.ruoyi.sim.domain.vo;
+
+import com.ruoyi.sim.domain.RealExamCollection;
+
+public class RealExamCollectionVo extends RealExamCollection {
+
+    /**
+     * 班级Id数组
+     */
+    private Long[] clazzIds;
+
+    public Long[] getClazzIds() {
+        return clazzIds;
+    }
+
+    public void setClazzIds(Long[] clazzIds) {
+        this.clazzIds = clazzIds;
+    }
+}

+ 18 - 0
ruoyi-sim/src/main/java/com/ruoyi/sim/domain/vo/StudentRealExamIngVo.java

@@ -0,0 +1,18 @@
+package com.ruoyi.sim.domain.vo;
+
+/**
+ * [学生]正在考试页面Vo。
+ */
+public class StudentRealExamIngVo {
+
+    private Long remainingMilliseconds;
+
+
+    public Long getRemainingMilliseconds() {
+        return remainingMilliseconds;
+    }
+
+    public void setRemainingMilliseconds(Long remainingMilliseconds) {
+        this.remainingMilliseconds = remainingMilliseconds;
+    }
+}

+ 4 - 0
ruoyi-sim/src/main/java/com/ruoyi/sim/domain/vo/StudentRealExamPostVo.java

@@ -0,0 +1,4 @@
+package com.ruoyi.sim.domain.vo;
+
+public class StudentRealExamPostVo {
+}

+ 87 - 0
ruoyi-sim/src/main/java/com/ruoyi/sim/domain/vo/StudentRealExamPreVo.java

@@ -0,0 +1,87 @@
+package com.ruoyi.sim.domain.vo;
+
+import com.ruoyi.sim.domain.*;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+
+/**
+ * [学生]准备考试页面Vo。
+ */
+public class StudentRealExamPreVo {
+
+    private RealExam realExam;
+
+    private RealExamCollection realExamCollection;
+
+    private Sim sim;
+
+    private Student student;
+
+    private Seat seat;
+    /**
+     * 是否可以下一步进入考试。
+     */
+    private boolean next = false;
+
+    public StudentRealExamPreVo() {
+    }
+
+    public RealExam getRealExam() {
+        return realExam;
+    }
+
+    public void setRealExam(RealExam realExam) {
+        this.realExam = realExam;
+    }
+
+    public RealExamCollection getRealExamCollection() {
+        return realExamCollection;
+    }
+
+    public void setRealExamCollection(RealExamCollection realExamCollection) {
+        this.realExamCollection = realExamCollection;
+    }
+
+    public Sim getSim() {
+        return sim;
+    }
+
+    public void setSim(Sim sim) {
+        this.sim = sim;
+    }
+
+    public Student getStudent() {
+        return student;
+    }
+
+    public void setStudent(Student student) {
+        this.student = student;
+    }
+
+    public Seat getSeat() {
+        return seat;
+    }
+
+    public void setSeat(Seat seat) {
+        this.seat = seat;
+    }
+
+    public boolean isNext() {
+        return next;
+    }
+
+    public void setNext(boolean next) {
+        this.next = next;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this)
+                .append("realExam", realExam)
+                .append("realExamCollection", realExamCollection)
+                .append("sim", sim)
+                .append("student", student)
+                .append("seat", seat)
+                .append("next", next)
+                .toString();
+    }
+}

+ 12 - 0
ruoyi-sim/src/main/java/com/ruoyi/sim/domain/vo/StudentRealExamVo.java

@@ -0,0 +1,12 @@
+package com.ruoyi.sim.domain.vo;
+
+import com.ruoyi.sim.domain.RealExam;
+import com.ruoyi.sim.domain.RealExamCollection;
+
+public class StudentRealExamVo {
+
+    private RealExam exam;
+
+    private RealExamCollection examCollection;
+
+}

+ 109 - 0
ruoyi-sim/src/main/java/com/ruoyi/sim/service/impl/CommReceiveService.java

@@ -0,0 +1,109 @@
+package com.ruoyi.sim.service.impl;
+
+import com.ruoyi.sim.domain.Fault;
+import com.ruoyi.sim.domain.RealExamFault;
+import com.ruoyi.sim.domain.Sim;
+import com.ruoyi.sim.domain.SimMsg;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Objects;
+
+@Service
+// 多实例
+// 异步调用
+// @Scope("prototype")
+public class CommReceiveService {
+
+    private static final Logger l = LoggerFactory.getLogger(CommReceiveService.class);
+    @Autowired
+    private RealExamService realExamService;
+    @Autowired
+    private RealExamFaultService realExamFaultService;
+    @Autowired
+    private SimService simService;
+
+    /**
+     * 只要返回信息,即认为在线。
+     *
+     * @param sm
+     * @param s
+     */
+    public void checkOneSimState(SimMsg sm, Sim s) {
+        if (Objects.isNull(sm)) {
+
+        }
+        if (!StringUtils.isEmpty(sm.getReceiveMsg())) {
+            Sim f = simService.selectSimBySimId(s.getSimId());
+            simService.updateSimStateBySimId(s.getSimId(), Sim.STATE_ONLINE);
+        }
+    }
+
+    public void clearOneFault(SimMsg sm, Sim s, RealExamFault reF, Fault f) {
+        // check
+
+        //
+        if (reF != null) {
+            reF.setRefState(RealExamFault.REF_STATE_CLEARED);
+            realExamFaultService.updateRealExamFault(reF);
+        }
+    }
+
+    /**
+     * 设置出题值。
+     *
+     * @param sm
+     * @param s
+     * @param reF
+     * @param f
+     */
+    public void setFaultQuestionValue(SimMsg sm, Sim s, RealExamFault reF, Fault f) {
+        // check
+
+        //
+        String faultQuestionValue = parseGetData(sm.getReceiveMsg());
+        l.info("faultQuestionValue = {}", faultQuestionValue);
+        reF.setRefState(RealExamFault.REF_STATE_WRITTEN);
+        reF.setSimFaultQuestionValue(faultQuestionValue);
+        realExamFaultService.updateRealExamFault(reF);
+    }
+
+    /**
+     * 设置答题值。
+     *
+     * @param sm
+     * @param s
+     * @param reF
+     * @param f
+     */
+    public void setFaultAnswerValue(SimMsg sm, Sim s, RealExamFault reF, Fault f) {
+        // check
+        if (reF == null) {
+            l.info("reF null!");
+            return;
+        }
+        //
+        String faultAnswerValue = parseGetData(sm.getReceiveMsg());
+        l.info("faultAnswerValue = {}", faultAnswerValue);
+        reF.setRefState(RealExamFault.REF_STATE_LOOP_READ);
+        reF.setSimFaultAnswerValue(faultAnswerValue);
+        realExamFaultService.updateRealExamFault(reF);
+    }
+
+    /**
+     * 截取
+     *
+     * @param receiveMsg
+     * @return
+     */
+    public String parseGetData(String receiveMsg) {
+        if (StringUtils.isEmpty(receiveMsg)) {
+            return "";
+        }
+        return StringUtils.substring(receiveMsg, 10, 18);
+    }
+
+}

+ 530 - 0
ruoyi-sim/src/main/java/com/ruoyi/sim/service/impl/CommSendService.java

@@ -0,0 +1,530 @@
+package com.ruoyi.sim.service.impl;
+
+import com.ruoyi.sim.config.SimConfig;
+import com.ruoyi.sim.domain.*;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketTimeoutException;
+import java.util.List;
+import java.util.Objects;
+
+import static com.ruoyi.sim.service.impl.CommSendService.Const.*;
+
+/**
+ * 硬件通信
+ * send service.
+ */
+@Service
+public class CommSendService {
+
+    interface Const {
+
+        String ROUTER_IP = "127.0.0.1";
+        String IP = "123.112.16.165";
+        int PORT = 8899;
+        /**
+         * 报文长度
+         */
+        int MSG_LENGTH = 20;
+
+        String PREFIX = "AA";
+
+        String SUFFIX = "55";
+
+        /**
+         * orientation
+         */
+        String ORN_SEND = "01";
+
+        /**
+         * orientation
+         */
+        String ORN_RECEIVE = "02";
+
+        String CMD_DATA_PLACE_HOLDER = "00000000";
+
+        /**
+         * 故障下发
+         */
+        String CMD_SET_FAULT = "01";
+        /**
+         * 故障清清除
+         */
+        String CMD_CLEAR_FAULT = "02";
+        /**
+         * 设备类型读取
+         */
+        String CMD_READ_TYPE = "03";
+        /**
+         * 状态读取 RESISTANCE电阻值
+         */
+        String CMD_READ_FAULT_RESISTANCE = "03";
+
+        String CMD_ID_GET_SN = "B1";
+        int LENGTH_2 = 2;
+        int LENGTH_8 = 8;
+        int LENGTH_20 = 20;
+    }
+
+    private static final Logger l = LoggerFactory.getLogger(CommSendService.class);
+    /**
+     * 缓存的Socket连接。
+     */
+    private Socket cachedSocket = null;
+    @Autowired
+    private CommReceiveService simReceiveService;
+    @Autowired
+    private SimService simService;
+    @Autowired
+    private FaultService faultService;
+    @Autowired
+    private RealExamService realExamService;
+    @Autowired
+    private RealExamFaultService realExamFaultService;
+    @Autowired
+    private SimConfig sConfig;
+
+    /**
+     * 初始化方法,项目启动后自动运行。
+     */
+    public void init() {
+        //
+        try {
+            if (!isReachable(ROUTER_IP)) {
+                // todo:ping 不通。
+            }
+            if (!isReachable(IP)) {
+                // todo:ping 不通。
+            }
+            openSocket();
+            //
+            checkAllSimState();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 定时任务。
+     */
+    public void scheduledLoopRead() {
+        readAll();
+    }
+
+    public void readAll() {
+        List<RealExam> listRE = realExamService.listAllStatus(RealExam.STATE_ANSWERING);
+        listRE.forEach(e -> {
+            if (e == null) {
+                return;
+            }
+            List<RealExamFault> listREF = realExamFaultService.listAllType2YesLoopReadState(e.getExamId());
+            listREF.forEach(ref -> {
+                Sim s = simService.selectSimBySimId(e.getSimId());
+                Fault f = faultService.selectFaultByFaultId(ref.getFaultId());
+                if (f != null &&
+                        f.getFaultType().equals(Fault.TYPE_3) &&
+                        f.getFaultState().equals(Fault.STATE_ENABLE)
+                )
+                    readOneFaultResistance(s, ref, f);
+            });
+        });
+    }
+
+    /**
+     * Async version.
+     */
+    @Async("tp-comm")
+    public void readAllAsync() {
+        readAll();
+    }
+
+    public void readOneExamAtLast(RealExam re) {
+        List<RealExamFault> listREF = realExamFaultService.listAllType2YesLoopReadState(re.getExamId());
+        listREF.forEach(ref -> {
+            Sim s = simService.selectSimBySimId(re.getSimId());
+            Fault f = faultService.selectFaultByFaultId(ref.getFaultId());
+            readOneFaultResistance(s, ref, f);
+        });
+        realExamService.updateOneState(re, RealExam.STATE_SUBMITTED);
+    }
+
+    /**
+     * 定时任务。
+     */
+    public void scheduledCheckAllSimState() {
+        checkAllSimState();
+    }
+
+    /**
+     * 查找所有没有被手动禁用,并order by sim_num的模拟器列表。检查所有模拟器状态。
+     */
+    public void checkAllSimState() {
+        List<Sim> list = simService.listAllEnable();
+        list.forEach(s -> {
+            checkOneSimState(s);
+        });
+    }
+
+    @Async()
+    public void checkAllSimStateAsync() {
+
+    }
+
+    public void checkOneSimState(Sim s) {
+        l.info(s.toString());
+        // check todo:
+        if (Objects.isNull(s)) {
+            return;
+        }
+        //
+        try {
+            SimMsg sm = new SimMsg();
+            String sendMsg = buildSendMsgReadSimType(s.getSimNum());
+            sm.setSendMsg(sendMsg);
+            String receiveMsg = send(sendMsg, s);
+            sm.setReceiveMsg(receiveMsg);
+            simReceiveService.checkOneSimState(sm, s);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 清除一个考试的,对应的某型号一台模拟器的,所有设备故障。
+     *
+     * @param re
+     */
+    public void clearListFaultByRealExam(RealExam re) {
+        // check
+        if (Objects.isNull(re)) {
+
+        }
+        //
+        List<RealExamFault> list = realExamFaultService.listAllType2InitStateByExamId(re.getExamId());
+        list.forEach(ref -> {
+            Fault f = faultService.selectFaultByFaultId(ref.getFaultId());
+            if (faultService.isDisable(f.getFaultId())) {
+                l.warn("故障{}-Disable", ref.getFaultId());
+                return;
+            }
+            l.info("f.toString() = " + f.toString());
+            Sim s = simService.selectSimBySimId(re.getSimId());
+            l.info("s.toString() = " + s.toString());
+            // check
+            if (Objects.isNull(f)) {
+
+            }
+            clearOneFault(s, ref, f);
+        });
+    }
+
+    /**
+     * Async version.
+     *
+     * @param re
+     */
+    @Async("tp-comm")
+    public void clearListFaultByRealExamAsync(RealExam re) {
+        clearListFaultByRealExam(re);
+    }
+
+    public void clearAll() {
+        // todo:
+        simService.listAllEnable().forEach(s -> {
+            String simType = s.getSimType();
+            List<Fault> listF = faultService.listAllType3EnableBySimType(simType);
+            listF.forEach(f -> {
+                clearOneFault(s, null, f);
+            });
+        });
+    }
+
+    /**
+     * @param s
+     * @param reF 可以为空,表示不关联考试的。
+     * @param f
+     */
+    public void clearOneFault(Sim s, RealExamFault reF, Fault f) {
+        // check todo:
+
+        //
+        try {
+            // step1
+            SimMsg sm1 = new SimMsg();
+            String sendMsg1 = buildSendMsgClearFault(s.getSimNum(), f.getBindHardwareMsg());
+            sm1.setSendMsg(sendMsg1);
+            String receiveMsg1 = send(sendMsg1, s);
+            sm1.setReceiveMsg(receiveMsg1);
+            simReceiveService.clearOneFault(sm1, s, reF, f);
+            // step2
+            if (reF != null && realExamFaultService.isState(reF.getRefId(), RealExamFault.REF_STATE_CLEARED)) {
+                writeOneFault(s, reF, f);
+            }
+        } catch (SocketTimeoutException e) {
+            throw new RuntimeException(e);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+
+    public void writeOneFault(Sim s, RealExamFault ref, Fault f) {
+        try {
+            // 下发故障
+            SimMsg sm1 = new SimMsg();
+            String sendMsg1 = buildSendMsgWriteFault(s.getSimNum(), f.getBindHardwareMsg());
+            sm1.setSendMsg(sendMsg1);
+            String receiveMsg1 = send(sendMsg1, s);
+            sm1.setReceiveMsg(receiveMsg1);
+            // todo:
+
+            // 读取一次当前电阻代表值作为出题值。
+            SimMsg sm2 = new SimMsg();
+            String sendMsg2 = buildSendMsgReadFaultResistance(s.getSimNum(), f.getBindHardwareMsg());
+            sm2.setSendMsg(sendMsg2);
+            String receiveMsg2 = send(sendMsg2, s);
+            sm2.setReceiveMsg(receiveMsg2);
+            simReceiveService.setFaultQuestionValue(sm2, s, ref, f);
+            // 修改关联状态。
+            {
+                RealExamFault f1 = realExamFaultService.selectRealExamFaultByRefId(ref.getRefId());
+                f1.setRefState(RealExamFault.REF_STATE_LOOP_READ);
+                realExamFaultService.updateRealExamFault(f1);
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+
+    public void readOneFaultResistance(Sim s, RealExamFault reF, Fault f) {
+        try {
+            SimMsg sm = new SimMsg();
+            String sendMsg = buildSendMsgReadFaultResistance(s.getSimNum(), "03");
+            sm.setSendMsg(sendMsg);
+            String receiveMsg = send(sendMsg, s);
+            sm.setReceiveMsg(receiveMsg);
+            simReceiveService.setFaultAnswerValue(sm, s, reF, f);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public void test() {
+        try {
+            {
+                String sendMsg = buildSendMsgReadFaultResistance("01", "04");
+                send(sendMsg, null);
+            }
+            {
+                String sendMsg = buildSendMsgReadFaultResistance("01", "05");
+                send(sendMsg, null);
+            }
+            {
+                String sendMsg = buildSendMsgReadFaultResistance("01", "06");
+                send(sendMsg, null);
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 设备类型读取
+     *
+     * @param simNum sim.sim_num
+     */
+    public String buildSendMsgReadSimType(final String simNum) {
+        return buildSendMsg(simNum, CMD_READ_TYPE, CMD_ID_GET_SN);
+    }
+
+    /**
+     * 故障下发
+     *
+     * @param simNum          sim.sim_num
+     * @param bindHardwareMsg fault.bind_hardware_msg
+     */
+    public String buildSendMsgWriteFault(final String simNum, final String bindHardwareMsg) {
+        return buildSendMsg(simNum, CMD_SET_FAULT, bindHardwareMsg);
+    }
+
+    /**
+     * 状态读取
+     *
+     * @param simNum          sim.sim_num
+     * @param bindHardwareMsg fault.bind_hardware_msg
+     */
+    public String buildSendMsgReadFaultResistance(final String simNum, final String bindHardwareMsg) {
+        return buildSendMsg(simNum, CMD_READ_FAULT_RESISTANCE, bindHardwareMsg);
+    }
+
+    /**
+     * 故障清清除
+     *
+     * @param simNum          sim.sim_num
+     * @param bindHardwareMsg fault.bind_hardware_msg
+     */
+    public String buildSendMsgClearFault(final String simNum, final String bindHardwareMsg) {
+        return buildSendMsg(simNum, CMD_CLEAR_FAULT, bindHardwareMsg);
+    }
+
+    public String buildSendMsg(final String simNum, final String cmd, final String cmdId) {
+        return buildSendMsg(simNum, cmd, cmdId, CMD_DATA_PLACE_HOLDER);
+    }
+
+    public String buildSendMsg(final String simNum, final String cmd, final String cmdId, final String data) {
+        if (StringUtils.isEmpty(simNum) || StringUtils.isEmpty(cmd) || StringUtils.isEmpty(cmdId) || StringUtils.isEmpty(data)) {
+            throw new IllegalArgumentException("buildSendMsg isEmpty");
+        }
+        if (simNum.length() != LENGTH_2) {
+            throw new IllegalArgumentException("buildSendMsg length error");
+        }
+        if (cmd.length() != LENGTH_2) {
+            throw new IllegalArgumentException("buildSendMsg length error");
+        }
+        if (cmdId.length() != LENGTH_2) {
+            throw new IllegalArgumentException("buildSendMsg length error");
+        }
+        if (data.length() != LENGTH_8) {
+            throw new IllegalArgumentException("buildSendMsg length error");
+        }
+        StringBuffer m = new StringBuffer();
+        m.append(PREFIX);
+        m.append(simNum);
+        m.append(ORN_SEND);
+        m.append(cmd);
+        m.append(cmdId);
+        m.append(data);
+        m.append(SUFFIX);
+        final String mFinal = m.toString();
+        if (mFinal.length() != LENGTH_20) {
+            throw new IllegalArgumentException("buildSendMsg length error");
+        }
+        return mFinal;
+    }
+
+    /**
+     * send hex message
+     *
+     * @param sendMsg
+     * @param s       可以为空,更新最后发送/接收时间 用。
+     * @return
+     */
+    public synchronized String send(final String sendMsg, final Sim s) throws IOException {
+        l.info("sendMsg = " + sendMsg);
+        String receiveMsg = null;
+        if (cachedSocket == null) {
+            openSocket();
+        }
+        InputStream is = cachedSocket.getInputStream();
+        OutputStream os = cachedSocket.getOutputStream();
+        os.write(hexStrToByteArrs(sendMsg));
+        if (s != null) {
+            simService.updateLastSentTime(s);
+        }
+        byte[] buffer = new byte[1024];
+        int length = is.read(buffer);
+        StringBuffer sbHex = new StringBuffer();
+        for (int i = 0; i < length; i++) {
+            sbHex.append(String.format("%02X", buffer[i]));
+        }
+        receiveMsg = sbHex.toString();
+        l.info("receiveMsg = {}", receiveMsg);
+        if (!checkReceiveMsg(receiveMsg)) {
+            // todo:
+            l.warn("checkReceiveMsg fail receiveMsg = {}", receiveMsg);
+            return "";
+        }
+        if (s != null) {
+            simService.updateLastReceivedTime(s);
+        }
+        return receiveMsg;
+    }
+
+    public void openSocket() throws IOException {
+
+        if (cachedSocket == null) {
+            cachedSocket = new Socket(IP, PORT);
+            // setSoTimeout
+            // cachedSocket.setSoTimeout(1000);
+        }
+    }
+
+    /**
+     * todo:异常精细处理
+     *
+     * @throws IOException
+     */
+    public void closeSocket() throws IOException {
+        if (cachedSocket != null) {
+            cachedSocket.close();
+        }
+        cachedSocket = null;
+    }
+
+    public byte[] hexStrToByteArrs(String hexString) {
+//        if (StringUtils.isEmpty(hexString)) {
+//            return null;
+//        }
+        hexString = hexString.replaceAll(" ", "");
+        int len = hexString.length();
+        int index = 0;
+
+        byte[] bytes = new byte[len / 2];
+
+        while (index < len) {
+            String sub = hexString.substring(index, index + 2);
+            bytes[index / 2] = (byte) Integer.parseInt(sub, 16);
+            index += 2;
+        }
+        return bytes;
+    }
+
+    /**
+     * ping
+     *
+     * @param ipV4
+     * @return
+     * @throws IOException
+     */
+    public boolean isReachable(String ipV4) throws IOException {
+        InetAddress ia = InetAddress.getByName(ipV4);
+        return ia.isReachable(sConfig.getGatewayReachableTimeout());
+    }
+
+    /**
+     * check receiveMsg
+     *
+     * @param receiveMsg
+     * @return
+     */
+    public boolean checkReceiveMsg(String receiveMsg) {
+        if (StringUtils.isEmpty(receiveMsg)) {
+            return false;
+        }
+        if (receiveMsg.length() != CommSendService.Const.LENGTH_20) {
+            return false;
+        }
+        final String orn = StringUtils.substring(receiveMsg, 4, 6);
+        if (!CommSendService.Const.ORN_RECEIVE.equals(orn)) {
+            return false;
+        }
+        if (!StringUtils.startsWith(receiveMsg, CommSendService.Const.PREFIX)) {
+            return false;
+        }
+        if (!StringUtils.endsWith(receiveMsg, CommSendService.Const.SUFFIX)) {
+            return false;
+        }
+        return true;
+    }
+}

+ 22 - 0
ruoyi-sim/src/main/java/com/ruoyi/sim/service/impl/FaultService.java

@@ -94,6 +94,28 @@ public class FaultService {
     @Autowired
     private SimService simService;
 
+    public boolean isEnable(String faultId) {
+        Fault q = new Fault();
+        q.setFaultId(faultId);
+        Fault f = selectFaultByFaultId(faultId);
+        if (f == null) {
+            return false;
+        }
+        return (Fault.STATE_ENABLE.equals(f.getFaultState()));
+    }
+
+    public boolean isDisable(String faultId) {
+        return !isEnable(faultId);
+    }
+
+    public List<Fault> listAllType3EnableBySimType(String simType) {
+        Fault q = new Fault();
+        q.setSimType(simType);
+        q.setFaultType(Fault.TYPE_3);
+        q.setFaultState(Fault.STATE_ENABLE);
+        return selectFaultList(q);
+    }
+
     /**
      * 查询故障列表tree
      *

+ 0 - 276
ruoyi-sim/src/main/java/com/ruoyi/sim/service/impl/IotService.java

@@ -1,276 +0,0 @@
-package com.ruoyi.sim.service.impl;
-
-import com.ruoyi.sim.config.SimConfig;
-import com.ruoyi.sim.domain.Sim;
-import com.ruoyi.sim.domain.SimMsg;
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.LoggerFactory;
-import org.slf4j.Logger;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.InetAddress;
-import java.net.Socket;
-import java.util.Objects;
-
-import static com.ruoyi.sim.service.impl.IotService.Const.*;
-
-/**
- * 硬件通信
- * send service.
- */
-@Service
-public class IotService {
-
-    interface Const {
-
-        String ROUTER_IP = "127.0.0.1";
-        String IP = "123.112.16.165";
-        int PORT = 8899;
-        /**
-         * 报文长度
-         */
-        int MSG_LENGTH = 20;
-
-        String PREFIX = "AA";
-
-        String SUFFIX = "55";
-
-        /**
-         * orientation
-         */
-        String ORN_SEND = "01";
-
-        /**
-         * orientation
-         */
-        String ORN_RECEIVE = "02";
-
-        String CMD_DATA_PLACE_HOLDER = "00000000";
-
-        /**
-         * 故障下发
-         */
-        String CMD_SET_FAULT = "01";
-        /**
-         * 故障清清除
-         */
-        String CMD_CLEAR_FAULT = "02";
-        /**
-         * 设备类型读取
-         */
-        String CMD_READ_TYPE = "03";
-        /**
-         * 状态读取 RESISTANCE电阻值
-         */
-        String CMD_READ_FAULT_RESISTANCE = "03";
-
-        String CMD_ID_GET_SN = "B1";
-        int LENGTH_2 = 2;
-        int LENGTH_8 = 8;
-        int LENGTH_20 = 20;
-    }
-
-    private static final Logger l = LoggerFactory.getLogger(IotService.class);
-    /**
-     * 缓存的Socket连接。
-     */
-    private Socket cachedSocket = null;
-    @Autowired
-    private SimReceiveService simReceiveService;
-    @Autowired
-    private SimConfig sc;
-
-    /**
-     * 初始化方法,项目启动后自动运行。
-     */
-    public void init() {
-        //
-        try {
-            if (!isReachable(ROUTER_IP)) {
-                // todo:ping 不通。
-            }
-            if (!isReachable(IP)) {
-                // todo:ping 不通。
-            }
-            openSocket();
-            //
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * 定时。
-     */
-    public void scheduledCheckAllSimState() {
-
-    }
-
-    /**
-     * 查找所有没有被手动禁用,并order by sim_num的模拟器列表。检查所有模拟器状态。
-     */
-    public void checkAllSimState() {
-
-    }
-
-    public void checkOneSimState(final Sim s) {
-        if (Objects.isNull(s)) {
-            return;
-        }
-        try {
-            SimMsg sm = new SimMsg();
-            // "s.getSimNum()"
-            String sendMsg = buildSendMsgReadSimType("s.getSimNum()");
-            sm.setSendMsg(sendMsg);
-            String receiveMsg = send(sendMsg);
-            sm.setReceiveMsg(receiveMsg);
-            simReceiveService.checkOneSimState(sm);
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * 设备类型读取
-     *
-     * @param simNum sim.sim_num
-     */
-    public String buildSendMsgReadSimType(final String simNum) {
-        return buildSendMsg(simNum, CMD_READ_TYPE, CMD_ID_GET_SN);
-    }
-
-    /**
-     * 故障下发
-     *
-     * @param simNum          sim.sim_num
-     * @param bindHardwareMsg fault.bind_hardware_msg
-     */
-    public String buildSendMsgWriteFault(final String simNum, final String bindHardwareMsg) {
-        return buildSendMsg(simNum, CMD_SET_FAULT, bindHardwareMsg);
-    }
-
-    /**
-     * 状态读取
-     *
-     * @param simNum          sim.sim_num
-     * @param bindHardwareMsg fault.bind_hardware_msg
-     */
-    public String buildSendMsgReadFaultResistance(final String simNum, final String bindHardwareMsg) {
-        return buildSendMsg(simNum, CMD_READ_FAULT_RESISTANCE, bindHardwareMsg);
-    }
-
-    /**
-     * 故障清清除
-     *
-     * @param simNum          sim.sim_num
-     * @param bindHardwareMsg fault.bind_hardware_msg
-     */
-    public String buildSendMsgClearFault(final String simNum, final String bindHardwareMsg) {
-        return buildSendMsg(simNum, CMD_CLEAR_FAULT, bindHardwareMsg);
-    }
-
-    public String buildSendMsg(final String simNum, final String cmd, final String cmdId) {
-        return buildSendMsg(simNum, cmd, cmdId, CMD_DATA_PLACE_HOLDER);
-    }
-
-    public String buildSendMsg(final String simNum, final String cmd, final String cmdId, final String data) {
-        if (StringUtils.isEmpty(simNum) || StringUtils.isEmpty(cmd) || StringUtils.isEmpty(cmdId) || StringUtils.isEmpty(data)) {
-            throw new IllegalArgumentException("buildSendMsg isEmpty");
-        }
-        if (simNum.length() != LENGTH_2 || cmd.length() != LENGTH_2 || cmdId.length() != LENGTH_2 || data.length() != LENGTH_8) {
-            throw new IllegalArgumentException("buildSendMsg length error");
-        }
-        StringBuffer m = new StringBuffer();
-        m.append(PREFIX);
-        m.append(simNum);
-        m.append(ORN_SEND);
-        m.append(cmd);
-        m.append(cmdId);
-        m.append(data);
-        m.append(SUFFIX);
-        final String mFinal = m.toString();
-        if (mFinal.length() != LENGTH_20) {
-            throw new IllegalArgumentException("buildSendMsg length error");
-        }
-        return mFinal;
-    }
-
-    /**
-     * send hex message
-     *
-     * @param sendMsg
-     * @return
-     */
-    public String send(final String sendMsg) throws IOException {
-        l.info("sendMsg = " + sendMsg);
-        String receiveMsg = null;
-        if (cachedSocket == null) {
-            openSocket();
-        }
-        InputStream is = cachedSocket.getInputStream();
-        OutputStream os = cachedSocket.getOutputStream();
-        os.write(hexStrToByteArrs(sendMsg));
-        byte[] buffer = new byte[1024];
-        int length = is.read(buffer);
-        StringBuffer sbHex = new StringBuffer();
-        for (int i = 0; i < length; i++) {
-            sbHex.append(String.format("%02X", buffer[i]));
-        }
-        receiveMsg = sbHex.toString();
-        l.info("receiveMsg = " + receiveMsg);
-        return receiveMsg;
-    }
-
-    public void openSocket() throws IOException {
-
-        if (cachedSocket == null) {
-            cachedSocket = new Socket(IP, PORT);
-        }
-    }
-
-    /**
-     * todo:异常精细处理
-     *
-     * @throws IOException
-     */
-    public void closeSocket() throws IOException {
-        if (cachedSocket != null) {
-            cachedSocket.close();
-        }
-        cachedSocket = null;
-    }
-
-    public byte[] hexStrToByteArrs(String hexString) {
-//        if (StringUtils.isEmpty(hexString)) {
-//            return null;
-//        }
-        hexString = hexString.replaceAll(" ", "");
-        int len = hexString.length();
-        int index = 0;
-
-        byte[] bytes = new byte[len / 2];
-
-        while (index < len) {
-            String sub = hexString.substring(index, index + 2);
-            bytes[index / 2] = (byte) Integer.parseInt(sub, 16);
-            index += 2;
-        }
-        return bytes;
-    }
-
-    /**
-     * ping
-     *
-     * @param ipV4
-     * @return
-     * @throws IOException
-     */
-    public boolean isReachable(String ipV4) throws IOException {
-        InetAddress ia = InetAddress.getByName(ipV4);
-        return ia.isReachable(sc.getGatewayReachableTimeout());
-    }
-}

+ 212 - 1
ruoyi-sim/src/main/java/com/ruoyi/sim/service/impl/RealExamCollectionService.java

@@ -1,12 +1,22 @@
 package com.ruoyi.sim.service.impl;
 
+import java.util.ArrayList;
 import java.util.List;
 
+import cn.ele6.catalyzer.ruoyi.custom.BaseService;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
 import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.sim.domain.vo.RealExamCollectionVo;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import com.ruoyi.sim.mapper.RealExamCollectionMapper;
 import com.ruoyi.sim.domain.RealExamCollection;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.RequestBody;
 
 /**
  * 考试集合Service业务层处理
@@ -15,7 +25,7 @@ import com.ruoyi.sim.domain.RealExamCollection;
  * @date 2024-12-17
  */
 @Service
-public class RealExamCollectionService {
+public class RealExamCollectionService extends BaseService {
     @Autowired
     private RealExamCollectionMapper realExamCollectionMapper;
 
@@ -80,4 +90,205 @@ public class RealExamCollectionService {
     public int deleteRealExamCollectionByExamCollectionId(Long examCollectionId) {
         return realExamCollectionMapper.deleteRealExamCollectionByExamCollectionId(examCollectionId);
     }
+
+    // -------------------------------- tom add  --------------------------------
+
+    /**
+     * [教师][分页]查询考试集合列表
+     *
+     * @param p
+     * @return
+     */
+    public AjaxResult listExamByTeacher(RealExamCollection p) {
+        startPage();
+        p.setExamCollectionType(RealExamCollection.Type.EXAM);
+        List<RealExamCollectionVo> list = new ArrayList<>();
+        realExamCollectionMapper.selectRealExamCollectionList(p).forEach((RealExamCollection s) -> {
+            RealExamCollectionVo t = new RealExamCollectionVo();
+            BeanUtils.copyProperties(s, t);
+            list.add(t);
+        });
+        return AjaxResult.success(list);
+    }
+
+    /**
+     * [教师][分页]查询练习集合列表
+     *
+     * @param p
+     * @return
+     */
+    public AjaxResult listExerciseByTeacher(RealExamCollection p) {
+        startPage();
+        p.setExamCollectionType(RealExamCollection.Type.EXERCISE);
+        List<RealExamCollectionVo> list = new ArrayList<>();
+        realExamCollectionMapper.selectRealExamCollectionList(p).forEach((RealExamCollection s) -> {
+            RealExamCollectionVo t = new RealExamCollectionVo();
+            BeanUtils.copyProperties(s, t);
+            list.add(t);
+        });
+        return AjaxResult.success(list);
+    }
+
+    /**
+     * [教师]获取考试集合详细信息
+     */
+    public AjaxResult getExamInfoByTeacher(Long id) {
+        RealExamCollection f = realExamCollectionMapper.
+                selectRealExamCollectionByExamCollectionId(id);
+        return AjaxResult.success(f);
+    }
+
+    /**
+     * [教师]获取练习集合详细信息
+     */
+    public AjaxResult getExerciseInfoByTeacher(Long id) {
+        RealExamCollection f = realExamCollectionMapper.
+                selectRealExamCollectionByExamCollectionId(id);
+        return AjaxResult.success(f);
+    }
+
+    /**
+     * [教师]新增考试集合
+     *
+     * @param vo
+     * @return
+     */
+    public AjaxResult addExam(@RequestBody RealExamCollectionVo vo) {
+        // check
+        if (StringUtils.isBlank(vo.getExamCollectionName())) {
+
+        }
+        //
+        RealExamCollection p = new RealExamCollection();
+        BeanUtils.copyProperties(vo, p);
+        p.setExamCollectionType(RealExamCollection.Type.EXAM);
+        insertRealExamCollection(p);
+        return AjaxResult.success();
+    }
+
+    /**
+     * [教师]新增练习集合
+     *
+     * @param vo
+     * @return
+     */
+    public AjaxResult addExercise(@RequestBody RealExamCollectionVo vo) {
+        // check
+
+        //
+        RealExamCollection p = new RealExamCollection();
+        BeanUtils.copyProperties(vo, p);
+        p.setExamCollectionType(RealExamCollection.Type.EXERCISE);
+        insertRealExamCollection(p);
+        return AjaxResult.success();
+    }
+
+    /**
+     * [教师]修改考试集合
+     *
+     * @param vo
+     * @return
+     */
+    public AjaxResult editExam(@RequestBody RealExamCollectionVo vo) {
+        // check
+
+        //
+        RealExamCollection p = new RealExamCollection();
+        BeanUtils.copyProperties(vo, p);
+        p.setExamCollectionType(RealExamCollection.Type.EXAM);
+        updateRealExamCollection(p);
+        // todo:更新关联
+
+        return AjaxResult.success();
+    }
+
+    /**
+     * [教师]修改练习集合
+     *
+     * @param vo
+     * @return
+     */
+    public AjaxResult editExercise(@RequestBody RealExamCollectionVo vo) {
+        // check
+
+        // do.
+        RealExamCollection p = new RealExamCollection();
+        BeanUtils.copyProperties(vo, p);
+        p.setExamCollectionType(RealExamCollection.Type.EXERCISE);
+        updateRealExamCollection(p);
+        // todo:更新关联
+
+        return AjaxResult.success();
+    }
+
+    /**
+     * [教师]删除多个考试集合
+     *
+     * @param ids
+     * @return
+     */
+    public AjaxResult deleteExams(Long[] ids) {
+        // check
+
+        // do.
+        deleteRealExamCollectionByExamCollectionIds(ids);
+        // todo:更新关联
+        return AjaxResult.success();
+    }
+
+    /**
+     * [教师]删除多个练习集合
+     *
+     * @param ids
+     * @return
+     */
+    public AjaxResult deleteExercises(Long[] ids) {
+        // check
+
+        // do.
+        deleteRealExamCollectionByExamCollectionIds(ids);
+        // todo:更新关联
+        return AjaxResult.success();
+    }
+
+    /**
+     * [教师]打开考试集合
+     *
+     * @param id
+     * @return
+     */
+    @Transactional
+    public AjaxResult openExam(Long id) {
+        // check
+        int countOpened = 0;
+        {
+            RealExamCollection q = new RealExamCollection();
+            q.setExamCollectionState(RealExamCollection.State.OPENED);
+            l.info("q = {}", q);
+            countOpened = selectRealExamCollectionList(q).size();
+        }
+        l.info("countOpened = {}", countOpened);
+        if (countOpened > 0) {
+            return AjaxResult.error("已经有打开的考试!");
+        }
+        // check datetime
+        // do.
+        RealExamCollection f = selectRealExamCollectionByExamCollectionId(id);
+        f.setExamCollectionState(RealExamCollection.State.OPENED);
+        updateRealExamCollection(f);
+        return AjaxResult.success();
+    }
+
+    /**
+     * [教师]关闭考试集合
+     *
+     * @param id
+     * @return
+     */
+    public AjaxResult closeExam(Long id) {
+        RealExamCollection f = selectRealExamCollectionByExamCollectionId(id);
+        f.setExamCollectionState(RealExamCollection.State.CLOSED);
+        updateRealExamCollection(f);
+        return AjaxResult.success();
+    }
 }

+ 86 - 0
ruoyi-sim/src/main/java/com/ruoyi/sim/service/impl/RealExamFaultService.java

@@ -3,6 +3,8 @@ package com.ruoyi.sim.service.impl;
 import java.util.List;
 
 import com.ruoyi.common.utils.DateUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import com.ruoyi.sim.mapper.RealExamFaultMapper;
@@ -80,4 +82,88 @@ public class RealExamFaultService {
     public int deleteRealExamFaultByRefId(Long refId) {
         return realExamFaultMapper.deleteRealExamFaultByRefId(refId);
     }
+
+    // -------------------------------- tom add  --------------------------------
+
+    private static final Logger l = LoggerFactory.getLogger(RealExamFaultService.class);
+
+    /**
+     * 初始化状态的 关联列表。
+     *
+     * @param examId
+     * @return
+     */
+    public List<RealExamFault> listAllType2InitStateByExamId(Long examId) {
+        RealExamFault q = new RealExamFault();
+        q.setExamId(examId);
+        q.setRefType(RealExamFault.REF_TYPE_2);
+        q.setRefState(RealExamFault.REF_STATE_INIT);
+        return realExamFaultMapper.selectRealExamFaultList(q);
+    }
+
+    public List<RealExamFault> listAllType2YesLoopReadState(Long examId) {
+        RealExamFault q = new RealExamFault();
+        q.setExamId(examId);
+        q.setRefType(RealExamFault.REF_TYPE_2);
+        q.setRefState(RealExamFault.REF_STATE_LOOP_READ);
+        q.setFlag(RealExamFault.FLAG_YES);
+        return realExamFaultMapper.selectRealExamFaultList(q);
+    }
+
+    public List<RealExamFault> listAllType2Yes(Long examId) {
+        RealExamFault q = new RealExamFault();
+        q.setExamId(examId);
+        q.setRefType(RealExamFault.REF_TYPE_2);
+        q.setFlag(RealExamFault.FLAG_YES);
+        return realExamFaultMapper.selectRealExamFaultList(q);
+    }
+
+    public boolean isAllType2YesStateEqualWritten(long examId) {
+        List<RealExamFault> list = listAllType2Yes(examId);
+        for (RealExamFault ref : list) {
+            if (ref.getRefState() != RealExamFault.REF_STATE_WRITTEN) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public boolean isState(Long refId, String state) {
+        RealExamFault f = selectRealExamFaultByRefId(refId);
+        if (f == null) {
+            return false;
+        }
+        return state.equals(f.getRefState());
+    }
+
+    /**
+     * 计算减分。
+     *
+     * @param refId
+     */
+    public void calculateMinus(Long refId) {
+        RealExamFault f = selectRealExamFaultByRefId(refId);
+        if (f == null) {
+            throw new RuntimeException("calculateMinus");
+        }
+        if (!RealExamFault.FLAG_YES.equals(f.getFlag())) {
+            throw new RuntimeException("calculateMinus");
+        }
+        int minus = 0;
+        if (RealExamFault.REF_TYPE_1.equals(f.getRefType())) {
+            // todo:选择题的算减分
+        } else if (RealExamFault.REF_TYPE_2.equals(f.getRefType())) {
+            // 模拟器故障的算减分
+            if (!f.getChoiceQuestionValue().equals(f.getChoiceAnswerValue())) {
+                // 扣0分
+                minus = 0;
+            } else {
+                // 扣25分 故障未排除
+                minus = 25;
+            }
+        }
+        f.setMinus(minus);
+        // 更新减分数据。
+        updateRealExamFault(f);
+    }
 }

+ 171 - 1
ruoyi-sim/src/main/java/com/ruoyi/sim/service/impl/RealExamService.java

@@ -1,12 +1,17 @@
 package com.ruoyi.sim.service.impl;
 
 import java.util.List;
+import java.util.Objects;
 
+import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.sim.domain.*;
+import com.ruoyi.sim.domain.vo.StudentRealExamPostVo;
+import com.ruoyi.sim.domain.vo.StudentRealExamPreVo;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import com.ruoyi.sim.mapper.RealExamMapper;
-import com.ruoyi.sim.domain.RealExam;
+import org.springframework.transaction.annotation.Transactional;
 
 /**
  * 考试Service业务层处理
@@ -80,4 +85,169 @@ public class RealExamService {
     public int deleteRealExamByExamId(Long examId) {
         return realExamMapper.deleteRealExamByExamId(examId);
     }
+
+    // -------------------------------- tom add  --------------------------------
+    @Autowired
+    private StudentService studentService;
+    @Autowired
+    private SimService simService;
+    @Autowired
+    private SeatService seatService;
+    @Autowired
+    private RealExamCollectionService realExamCollectionService;
+    @Autowired
+    private RealExamFaultService realExamFaultService;
+    @Autowired
+    private CommSendService commSendService;
+
+    public List<RealExam> listAllStatus(String examStatus) {
+        RealExam q = new RealExam();
+        q.setExamStatus(examStatus);
+        return selectRealExamList(q);
+    }
+
+    @Transactional
+    public int updateOneState(RealExam re, final String state) {
+        RealExam q = selectRealExamByExamId(re.getExamId());
+        if (state.equals(RealExam.STATE_SUBMITTED)) {
+            // 关联故障list同步锁死。
+            realExamFaultService.listAllType2YesLoopReadState(q.getExamId())
+                    .forEach(ref -> {
+                        ref.setRefState(RealExamFault.REF_STATE_FINISH);
+                        realExamFaultService.updateRealExamFault(ref);
+                    });
+        }
+        q.setExamStatus(state);
+        return updateRealExam(q);
+    }
+
+    /**
+     * 计算减分(不包括超时)。汇总到deduction_total_score字段。
+     *
+     * @param realExamId
+     */
+    public void calculate(Long realExamId) {
+        int minus = 0;
+        RealExam re = realExamMapper.selectRealExamByExamId(realExamId);
+
+        // 排除故障部分
+
+
+        // 维修报告选择部分
+
+        // 超时部分
+        int timeoutMinute = 0;
+    }
+
+    /**
+     * [学生]进入考试。
+     *
+     * @return
+     */
+    public AjaxResult studentEnterRealExam() {
+        RealExam re = null;
+        return AjaxResult.success(re);
+    }
+
+    /**
+     * [轮询][学生]准备考试界面。
+     *
+     * @param realExamId
+     * @return
+     */
+    public StudentRealExamPreVo studentPrepareRealExam(Long realExamId) {
+        // check
+        if (realExamId == null || realExamId == 0) {
+            // todo:
+        }
+        //
+        RealExam re = selectRealExamByExamId(realExamId);
+        if (re == null) {
+            // todo:
+        }
+        // todo: 日期,不可进入考试。
+        //
+        // todo: 验证学生登录身份
+        Objects.requireNonNull(re);
+        RealExamCollection collection =
+                realExamCollectionService.selectRealExamCollectionByExamCollectionId(re.getExamCollectionId());
+        // check collection
+        Sim sim = simService.selectSimBySimId(re.getSimId());
+        // check sim
+        Student student = studentService.selectStudentByUserId(re.getUserId());
+        // check student
+        Seat seat = seatService.selectSeatBySeatId(re.getSeatId());
+        // check seat
+        StudentRealExamPreVo v = new StudentRealExamPreVo();
+        v.setRealExam(re);
+        v.setRealExamCollection(collection);
+        v.setSim(sim);
+        v.setStudent(student);
+        v.setSeat(seat);
+        boolean next = studentPrepareRealExamCheck(v);
+        v.setNext(next);
+        if (!next) {
+            // 执行模拟器通信,让模拟器准备好。
+            // async execute.
+            commSendService.clearListFaultByRealExamAsync(re);
+        }
+        return v;
+    }
+
+    public boolean studentPrepareRealExamCheck(StudentRealExamPreVo v) {
+        if (v == null ||
+                v.getRealExam() == null ||
+                v.getRealExamCollection() == null ||
+                v.getSim() == null ||
+                v.getStudent() == null ||
+                v.getSeat() == null) {
+            return false;
+        }
+        // todo:在考试日期内。
+        // check 一个模拟器的所有选中故障点位都下发成功,准备是否可以
+        //
+        // todo:??
+        // 学生答题中可以再次进入。
+        if (v.getRealExam().getExamStatus() == RealExam.STATE_SIM_PREPARE_OK ||
+                v.getRealExam().getExamStatus() == RealExam.STATE_ANSWERING ||
+                v.getSim().getSimState() == Sim.STATE_ONLINE
+        ) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * [轮询][学生]正在考试界面。
+     *
+     * @param realExamId
+     * @return
+     */
+    public StudentRealExamPreVo studentIngRealExam(Long realExamId) {
+        return null;
+    }
+
+    /**
+     * [学生]交卷
+     *
+     * @param realExamId
+     * @return
+     */
+    public AjaxResult studentSubmitRealExam(Long realExamId) {
+        // 最后检查一下模拟器状态。
+        
+        // 最后读取一下模拟器电阻值。
+        return AjaxResult.success();
+    }
+
+    /**
+     * [轮询][学生]结束考试界面。
+     *
+     * @param realExamId
+     * @return
+     */
+    public AjaxResult studentPostRealExam(Long realExamId) {
+        StudentRealExamPostVo vo = new StudentRealExamPostVo();
+        return AjaxResult.success(vo);
+    }
 }

+ 0 - 20
ruoyi-sim/src/main/java/com/ruoyi/sim/service/impl/SimReceiveService.java

@@ -1,20 +0,0 @@
-package com.ruoyi.sim.service.impl;
-
-import com.ruoyi.sim.domain.SimMsg;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.context.annotation.Scope;
-import org.springframework.stereotype.Service;
-
-@Service
-// 多实例
-// 异步调用
-// @Scope("prototype")
-public class SimReceiveService {
-
-    private static final Logger l = LoggerFactory.getLogger(IotService.class);
-
-    public void checkOneSimState(SimMsg sm) {
-
-    }
-}

+ 31 - 0
ruoyi-sim/src/main/java/com/ruoyi/sim/service/impl/SimService.java

@@ -1,11 +1,13 @@
 package com.ruoyi.sim.service.impl;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 
 import com.ruoyi.common.utils.DateUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import com.ruoyi.sim.mapper.SimMapper;
 import com.ruoyi.sim.domain.Sim;
@@ -86,6 +88,17 @@ public class SimService {
 
     // -------------------------------- tom add  --------------------------------
 
+    public List<Sim> listAllEnable() {
+        List<Sim> list = selectSimList(new Sim());
+        List<Sim> listR = new ArrayList<Sim>();
+        for (Sim o : list) {
+            if (!Sim.STATE_DISABLE.equals(o.getSimState())) {
+                listR.add(o);
+            }
+        }
+        return listR;
+    }
+
     public List<String> listSimTypes() {
         return Sim.TYPE_SET.stream().toList();
     }
@@ -158,4 +171,22 @@ public class SimService {
         }
         return count;
     }
+
+    @Async("tp-log")
+    public void updateLastSentTime(Sim s) {
+        if (s == null) {
+            return;
+        }
+        s.setLastSentTime(DateUtils.getNowDate());
+        updateSim(s);
+    }
+
+    @Async("tp-log")
+    public void updateLastReceivedTime(Sim s) {
+        if (s == null) {
+            return;
+        }
+        s.setLastReceivedTime(DateUtils.getNowDate());
+        updateSim(s);
+    }
 }

+ 3 - 4
ruoyi-sim/src/main/java/com/ruoyi/sim/service/impl/TaskService.java

@@ -1,6 +1,5 @@
 package com.ruoyi.sim.service.impl;
 
-import java.util.ArrayList;
 import java.util.List;
 
 import com.ruoyi.common.core.domain.AjaxResult;
@@ -67,7 +66,7 @@ public class TaskService {
             if (o == null) {
                 continue;
             }
-            if (Fault.FAULT_TYPE_3.equals(o.getFaultType())) {
+            if (Fault.TYPE_3.equals(o.getFaultType())) {
                 TaskFault tf = o.getTaskFault();
                 TaskFault tfQ = taskFaultService.selectUniqueTaskFault(taskId, tf.getFaultId());
                 // 存在就设置上数据库中TaskFault值。
@@ -129,7 +128,7 @@ public class TaskService {
                 if (ftv == null) {
                     continue;
                 }
-                if (!Fault.FAULT_TYPE_3.equals(ftv.getFaultType())) {
+                if (!Fault.TYPE_3.equals(ftv.getFaultType())) {
                     continue;
                 }
                 TaskFault tf = ftv.getTaskFault();
@@ -224,7 +223,7 @@ public class TaskService {
                 if (ftv == null) {
                     continue;
                 }
-                if (!Fault.FAULT_TYPE_3.equals(ftv.getFaultType())) {
+                if (!Fault.TYPE_3.equals(ftv.getFaultType())) {
                     continue;
                 }
                 TaskFault tf = ftv.getTaskFault();

+ 9 - 0
ruoyi-sim/src/main/resources/mapper/sim/FaultMapper.xml

@@ -9,6 +9,7 @@
         <result property="parentFaultId" column="parent_fault_id"/>
         <result property="simType" column="sim_type"/>
         <result property="faultType" column="fault_type"/>
+        <result property="faultState" column="fault_state"/>
         <result property="conflictFaultIds" column="conflict_fault_ids"/>
         <result property="replacePart" column="replace_part"/>
         <result property="replaceName" column="replace_name"/>
@@ -27,6 +28,7 @@
                parent_fault_id,
                sim_type,
                fault_type,
+               fault_state,
                conflict_fault_ids,
                replace_part,
                replace_name,
@@ -47,6 +49,7 @@
             <if test="parentFaultId != null  and parentFaultId != ''">and parent_fault_id = #{parentFaultId}</if>
             <if test="simType != null  and simType != ''">and sim_type = #{simType}</if>
             <if test="faultType != null  and faultType != ''">and fault_type = #{faultType}</if>
+            <if test="faultState != null  and faultState != ''">and fault_state = #{faultState}</if>
             <if test="conflictFaultIds != null  and conflictFaultIds != ''">and conflict_fault_ids =
                 #{conflictFaultIds}
             </if>
@@ -67,12 +70,16 @@
     </select>
 
     <insert id="insertFault" parameterType="Fault">
+        <selectKey keyProperty="faultId" order="AFTER" resultType="java.lang.String">
+            select LAST_INSERT_ID()
+        </selectKey>
         insert into sim_fault
         <trim prefix="(" suffix=")" suffixOverrides=",">
             <if test="faultId != null">fault_id,</if>
             <if test="parentFaultId != null and parentFaultId != ''">parent_fault_id,</if>
             <if test="simType != null and simType != ''">sim_type,</if>
             <if test="faultType != null">fault_type,</if>
+            <if test="faultState != null">fault_state,</if>
             <if test="conflictFaultIds != null and conflictFaultIds != ''">conflict_fault_ids,</if>
             <if test="replacePart != null">replace_part,</if>
             <if test="replaceName != null">replace_name,</if>
@@ -90,6 +97,7 @@
             <if test="parentFaultId != null and parentFaultId != ''">#{parentFaultId},</if>
             <if test="simType != null and simType != ''">#{simType},</if>
             <if test="faultType != null">#{faultType},</if>
+            <if test="faultState != null">#{faultState},</if>
             <if test="conflictFaultIds != null and conflictFaultIds != ''">#{conflictFaultIds},</if>
             <if test="replacePart != null">#{replacePart},</if>
             <if test="replaceName != null">#{replaceName},</if>
@@ -110,6 +118,7 @@
             <if test="parentFaultId != null and parentFaultId != ''">parent_fault_id = #{parentFaultId},</if>
             <if test="simType != null and simType != ''">sim_type = #{simType},</if>
             <if test="faultType != null">fault_type = #{faultType},</if>
+            <if test="faultState != null">fault_state = #{faultState},</if>
             <if test="conflictFaultIds != null and conflictFaultIds != ''">conflict_fault_ids = #{conflictFaultIds},
             </if>
             <if test="replacePart != null">replace_part = #{replacePart},</if>

+ 3 - 0
ruoyi-sim/src/main/resources/mapper/sim/MajorMapper.xml

@@ -32,6 +32,9 @@
     </select>
 
     <insert id="insertMajor" parameterType="Major" useGeneratedKeys="true" keyProperty="majorId">
+        <selectKey keyProperty="majorId" order="AFTER" resultType="java.lang.Long">
+            select LAST_INSERT_ID()
+        </selectKey>
         insert into sim_major
         <trim prefix="(" suffix=")" suffixOverrides=",">
             <if test="majorName != null and majorName != ''">major_name,</if>

+ 3 - 0
ruoyi-sim/src/main/resources/mapper/sim/RealExamCollectionDeptMapper.xml

@@ -32,6 +32,9 @@
 
     <insert id="insertRealExamCollectionDept" parameterType="RealExamCollectionDept" useGeneratedKeys="true"
             keyProperty="relId">
+        <selectKey keyProperty="relId" order="AFTER" resultType="java.lang.Long">
+            select LAST_INSERT_ID()
+        </selectKey>
         insert into sim_real_exam_collection_dept
         <trim prefix="(" suffix=")" suffixOverrides=",">
             <if test="examCollectionId != null">exam_collection_id,</if>

+ 11 - 0
ruoyi-sim/src/main/resources/mapper/sim/RealExamCollectionMapper.xml

@@ -9,6 +9,7 @@
         <result property="simType" column="sim_type"/>
         <result property="questionSettingMethod" column="question_setting_method"/>
         <result property="examCollectionType" column="exam_collection_type"/>
+        <result property="examCollectionState" column="exam_collection_state"/>
         <result property="examCollectionName" column="exam_collection_name"/>
         <result property="taskId" column="task_id"/>
         <result property="limitDuration" column="limit_duration"/>
@@ -27,6 +28,7 @@
                sim_type,
                question_setting_method,
                exam_collection_type,
+               exam_collection_state,
                exam_collection_name,
                task_id,
                limit_duration,
@@ -51,6 +53,9 @@
             <if test="examCollectionType != null  and examCollectionType != ''">and exam_collection_type =
                 #{examCollectionType}
             </if>
+            <if test="examCollectionState != null  and examCollectionState != ''">and exam_collection_state =
+                #{examCollectionState}
+            </if>
             <if test="examCollectionName != null  and examCollectionName != ''">and exam_collection_name like
                 concat('%', #{examCollectionName}, '%')
             </if>
@@ -69,11 +74,15 @@
 
     <insert id="insertRealExamCollection" parameterType="RealExamCollection" useGeneratedKeys="true"
             keyProperty="examCollectionId">
+        <selectKey keyProperty="examCollectionId" order="AFTER" resultType="java.lang.Long">
+            select LAST_INSERT_ID()
+        </selectKey>
         insert into sim_real_exam_collection
         <trim prefix="(" suffix=")" suffixOverrides=",">
             <if test="simType != null and simType != ''">sim_type,</if>
             <if test="questionSettingMethod != null and questionSettingMethod != ''">question_setting_method,</if>
             <if test="examCollectionType != null and examCollectionType != ''">exam_collection_type,</if>
+            <if test="examCollectionState != null">exam_collection_state,</if>
             <if test="examCollectionName != null and examCollectionName != ''">exam_collection_name,</if>
             <if test="taskId != null">task_id,</if>
             <if test="limitDuration != null">limit_duration,</if>
@@ -90,6 +99,7 @@
             <if test="simType != null and simType != ''">#{simType},</if>
             <if test="questionSettingMethod != null and questionSettingMethod != ''">#{questionSettingMethod},</if>
             <if test="examCollectionType != null and examCollectionType != ''">#{examCollectionType},</if>
+            <if test="examCollectionState != null">#{examCollectionState},</if>
             <if test="examCollectionName != null and examCollectionName != ''">#{examCollectionName},</if>
             <if test="taskId != null">#{taskId},</if>
             <if test="limitDuration != null">#{limitDuration},</if>
@@ -114,6 +124,7 @@
             <if test="examCollectionType != null and examCollectionType != ''">exam_collection_type =
                 #{examCollectionType},
             </if>
+            <if test="examCollectionState != null">exam_collection_state = #{examCollectionState},</if>
             <if test="examCollectionName != null and examCollectionName != ''">exam_collection_name =
                 #{examCollectionName},
             </if>

+ 3 - 0
ruoyi-sim/src/main/resources/mapper/sim/RealExamCompRequestMapper.xml

@@ -52,6 +52,9 @@
 
     <insert id="insertRealExamCompRequest" parameterType="RealExamCompRequest" useGeneratedKeys="true"
             keyProperty="relId">
+        <selectKey keyProperty="relId" order="AFTER" resultType="java.lang.Long">
+            select LAST_INSERT_ID()
+        </selectKey>
         insert into sim_real_exam_comp_request
         <trim prefix="(" suffix=")" suffixOverrides=",">
             <if test="examId != null">exam_id,</if>

+ 3 - 0
ruoyi-sim/src/main/resources/mapper/sim/RealExamFaultMapper.xml

@@ -73,6 +73,9 @@
     </select>
 
     <insert id="insertRealExamFault" parameterType="RealExamFault" useGeneratedKeys="true" keyProperty="refId">
+        <selectKey keyProperty="refId" order="AFTER" resultType="java.lang.Long">
+            select LAST_INSERT_ID()
+        </selectKey>
         insert into sim_real_exam_fault
         <trim prefix="(" suffix=")" suffixOverrides=",">
             <if test="examId != null">exam_id,</if>

+ 3 - 0
ruoyi-sim/src/main/resources/mapper/sim/RealExamMapper.xml

@@ -68,6 +68,9 @@
     </select>
 
     <insert id="insertRealExam" parameterType="RealExam">
+        <selectKey keyProperty="examId" order="AFTER" resultType="java.lang.Long">
+            select LAST_INSERT_ID()
+        </selectKey>
         insert into sim_real_exam
         <trim prefix="(" suffix=")" suffixOverrides=",">
             <if test="examId != null">exam_id,</if>

+ 3 - 0
ruoyi-sim/src/main/resources/mapper/sim/SeatMapper.xml

@@ -44,6 +44,9 @@
     </select>
 
     <insert id="insertSeat" parameterType="Seat" useGeneratedKeys="true" keyProperty="seatId">
+        <selectKey keyProperty="seatId" order="AFTER" resultType="java.lang.Long">
+            select LAST_INSERT_ID()
+        </selectKey>
         insert into sim_seat
         <trim prefix="(" suffix=")" suffixOverrides=",">
             <if test="seatNum != null">seat_num,</if>

+ 15 - 0
ruoyi-sim/src/main/resources/mapper/sim/SimMapper.xml

@@ -11,6 +11,8 @@
         <result property="simState" column="sim_state"/>
         <result property="simSn" column="sim_sn"/>
         <result property="simNum" column="sim_num"/>
+        <result property="lastSentTime" column="last_sent_time"/>
+        <result property="lastReceivedTime" column="last_received_time"/>
         <result property="createBy" column="create_by"/>
         <result property="createTime" column="create_time"/>
         <result property="updateBy" column="update_by"/>
@@ -25,6 +27,8 @@
                sim_state,
                sim_sn,
                sim_num,
+               last_sent_time,
+               last_received_time,
                create_by,
                create_time,
                update_by,
@@ -41,6 +45,8 @@
             <if test="simState != null  and simState != ''">and sim_state = #{simState}</if>
             <if test="simSn != null  and simSn != ''">and sim_sn = #{simSn}</if>
             <if test="simNum != null  and simNum != ''">and sim_num = #{simNum}</if>
+            <if test="lastSentTime != null ">and last_sent_time = #{lastSentTime}</if>
+            <if test="lastReceivedTime != null ">and last_received_time = #{lastReceivedTime}</if>
         </where>
     </select>
 
@@ -50,6 +56,9 @@
     </select>
 
     <insert id="insertSim" parameterType="Sim" useGeneratedKeys="true" keyProperty="simId">
+        <selectKey keyProperty="simId" order="AFTER" resultType="java.lang.Long">
+            select LAST_INSERT_ID()
+        </selectKey>
         insert into sim_sim
         <trim prefix="(" suffix=")" suffixOverrides=",">
             <if test="seatId != null">seat_id,</if>
@@ -57,6 +66,8 @@
             <if test="simState != null and simState != ''">sim_state,</if>
             <if test="simSn != null and simSn != ''">sim_sn,</if>
             <if test="simNum != null and simNum != ''">sim_num,</if>
+            <if test="lastSentTime != null">last_sent_time,</if>
+            <if test="lastReceivedTime != null">last_received_time,</if>
             <if test="createBy != null">create_by,</if>
             <if test="createTime != null">create_time,</if>
             <if test="updateBy != null">update_by,</if>
@@ -69,6 +80,8 @@
             <if test="simState != null and simState != ''">#{simState},</if>
             <if test="simSn != null and simSn != ''">#{simSn},</if>
             <if test="simNum != null and simNum != ''">#{simNum},</if>
+            <if test="lastSentTime != null">#{lastSentTime},</if>
+            <if test="lastReceivedTime != null">#{lastReceivedTime},</if>
             <if test="createBy != null">#{createBy},</if>
             <if test="createTime != null">#{createTime},</if>
             <if test="updateBy != null">#{updateBy},</if>
@@ -85,6 +98,8 @@
             <if test="simState != null and simState != ''">sim_state = #{simState},</if>
             <if test="simSn != null and simSn != ''">sim_sn = #{simSn},</if>
             <if test="simNum != null and simNum != ''">sim_num = #{simNum},</if>
+            <if test="lastSentTime != null">last_sent_time = #{lastSentTime},</if>
+            <if test="lastReceivedTime != null">last_received_time = #{lastReceivedTime},</if>
             <if test="createBy != null">create_by = #{createBy},</if>
             <if test="createTime != null">create_time = #{createTime},</if>
             <if test="updateBy != null">update_by = #{updateBy},</if>

+ 3 - 0
ruoyi-sim/src/main/resources/mapper/sim/SimMsg.xml

@@ -70,6 +70,9 @@
     </select>
 
     <insert id="insertSimMsg" parameterType="SimMsg" useGeneratedKeys="true" keyProperty="simMsgId">
+        <selectKey keyProperty="simMsgId" order="AFTER" resultType="java.lang.Long">
+            select LAST_INSERT_ID()
+        </selectKey>
         insert into sim_sim_msg
         <trim prefix="(" suffix=")" suffixOverrides=",">
             <if test="simId != null">sim_id,</if>

+ 3 - 0
ruoyi-sim/src/main/resources/mapper/sim/TaskFaultMapper.xml

@@ -32,6 +32,9 @@
     </select>
 
     <insert id="insertTaskFault" parameterType="TaskFault" useGeneratedKeys="true" keyProperty="relId">
+        <selectKey keyProperty="relId" order="AFTER" resultType="java.lang.Long">
+            select LAST_INSERT_ID()
+        </selectKey>
         insert into sim_task_fault
         <trim prefix="(" suffix=")" suffixOverrides=",">
             <if test="taskId != null">task_id,</if>

+ 1 - 1
ruoyi-sim/src/main/resources/mapper/sim/TaskMapper.xml

@@ -48,7 +48,7 @@
 
     <insert id="insertTask" parameterType="Task">
         <selectKey keyProperty="taskId" order="AFTER" resultType="java.lang.Long">
-            select last_insert_id()
+            select LAST_INSERT_ID()
         </selectKey>
         insert into sim_task
         <trim prefix="(" suffix=")" suffixOverrides=",">

Some files were not shown because too many files changed in this diff