hou 3 dagen geleden
bovenliggende
commit
621eb6a257
60 gewijzigde bestanden met toevoegingen van 6118 en 41 verwijderingen
  1. 328 0
      db/mysql/add_mes_device_fault_menu.sql
  2. 22 0
      db/mysql/add_mes_device_prevent_task_batch.sql
  3. 8 0
      db/mysql/rename_prevent_task_record_menu.sql
  4. 16 0
      src/main/java/com/jeesite/modules/mes/dao/MesDeviceFaultCateDao.java
  5. 15 0
      src/main/java/com/jeesite/modules/mes/dao/MesDeviceFaultDao.java
  6. 15 0
      src/main/java/com/jeesite/modules/mes/dao/MesDeviceFaultMaintainDao.java
  7. 15 0
      src/main/java/com/jeesite/modules/mes/dao/MesDeviceOeeCateDao.java
  8. 15 0
      src/main/java/com/jeesite/modules/mes/dao/MesDeviceOeeDao.java
  9. 6 1
      src/main/java/com/jeesite/modules/mes/dao/MesDevicePreventTaskDao.java
  10. 15 0
      src/main/java/com/jeesite/modules/mes/dao/MesDeviceVulnerableDao.java
  11. 274 0
      src/main/java/com/jeesite/modules/mes/entity/MesDeviceFault.java
  12. 60 0
      src/main/java/com/jeesite/modules/mes/entity/MesDeviceFaultCate.java
  13. 103 0
      src/main/java/com/jeesite/modules/mes/entity/MesDeviceFaultMaintain.java
  14. 1 0
      src/main/java/com/jeesite/modules/mes/entity/MesDeviceForm.java
  15. 120 0
      src/main/java/com/jeesite/modules/mes/entity/MesDeviceOee.java
  16. 57 0
      src/main/java/com/jeesite/modules/mes/entity/MesDeviceOeeCate.java
  17. 31 0
      src/main/java/com/jeesite/modules/mes/entity/MesDevicePreventTask.java
  18. 179 0
      src/main/java/com/jeesite/modules/mes/entity/MesDeviceVulnerable.java
  19. 88 0
      src/main/java/com/jeesite/modules/mes/service/MesDeviceFaultCateService.java
  20. 143 0
      src/main/java/com/jeesite/modules/mes/service/MesDeviceFaultMaintainService.java
  21. 159 0
      src/main/java/com/jeesite/modules/mes/service/MesDeviceFaultService.java
  22. 81 0
      src/main/java/com/jeesite/modules/mes/service/MesDeviceOeeCateService.java
  23. 148 0
      src/main/java/com/jeesite/modules/mes/service/MesDeviceOeeService.java
  24. 69 0
      src/main/java/com/jeesite/modules/mes/service/MesDevicePreventTaskService.java
  25. 137 0
      src/main/java/com/jeesite/modules/mes/service/MesDeviceVulnerableService.java
  26. 47 0
      src/main/java/com/jeesite/modules/mes/util/CommonUitl.java
  27. 119 0
      src/main/java/com/jeesite/modules/mes/web/MesDeviceFaultCateController.java
  28. 452 0
      src/main/java/com/jeesite/modules/mes/web/MesDeviceFaultController.java
  29. 167 0
      src/main/java/com/jeesite/modules/mes/web/MesDeviceFaultMaintainController.java
  30. 119 0
      src/main/java/com/jeesite/modules/mes/web/MesDeviceOeeCateController.java
  31. 249 0
      src/main/java/com/jeesite/modules/mes/web/MesDeviceOeeController.java
  32. 51 17
      src/main/java/com/jeesite/modules/mes/web/MesDevicePreventTaskController.java
  33. 153 0
      src/main/java/com/jeesite/modules/mes/web/MesDeviceVulnerableController.java
  34. 1 1
      src/main/resources/config/application.yml
  35. 18 0
      src/main/resources/mappings/modules/mes/MesDeviceFaultCateDao.xml
  36. 15 0
      src/main/resources/mappings/modules/mes/MesDeviceFaultDao.xml
  37. 17 0
      src/main/resources/mappings/modules/mes/MesDeviceFaultMaintainDao.xml
  38. 15 0
      src/main/resources/mappings/modules/mes/MesDeviceOeeCateDao.xml
  39. 18 0
      src/main/resources/mappings/modules/mes/MesDeviceOeeDao.xml
  40. 50 0
      src/main/resources/mappings/modules/mes/MesDevicePreventTaskDao.xml
  41. 15 0
      src/main/resources/mappings/modules/mes/MesDeviceVulnerableDao.xml
  42. 66 0
      src/main/resources/views/modules/mes/mesDeviceFaultCateForm.html
  43. 80 0
      src/main/resources/views/modules/mes/mesDeviceFaultCateList.html
  44. 178 0
      src/main/resources/views/modules/mes/mesDeviceFaultForm.html
  45. 209 0
      src/main/resources/views/modules/mes/mesDeviceFaultList.html
  46. 64 0
      src/main/resources/views/modules/mes/mesDeviceFaultMaintainForm.html
  47. 160 0
      src/main/resources/views/modules/mes/mesDeviceFaultMaintainList.html
  48. 440 0
      src/main/resources/views/modules/mes/mesDeviceFaultTj.html
  49. 342 0
      src/main/resources/views/modules/mes/mesDeviceFaultTj2.html
  50. 4 1
      src/main/resources/views/modules/mes/mesDeviceFormList.html
  51. 55 0
      src/main/resources/views/modules/mes/mesDeviceOeeCateForm.html
  52. 71 0
      src/main/resources/views/modules/mes/mesDeviceOeeCateList.html
  53. 83 0
      src/main/resources/views/modules/mes/mesDeviceOeeForm.html
  54. 123 0
      src/main/resources/views/modules/mes/mesDeviceOeeList.html
  55. 97 0
      src/main/resources/views/modules/mes/mesDeviceOeeTj.html
  56. 56 18
      src/main/resources/views/modules/mes/mesDevicePreventTaskList.html
  57. 2 3
      src/main/resources/views/modules/mes/mesDevicePreventTaskMyList.html
  58. 119 0
      src/main/resources/views/modules/mes/mesDeviceVulnerableDetail.html
  59. 167 0
      src/main/resources/views/modules/mes/mesDeviceVulnerableForm.html
  60. 191 0
      src/main/resources/views/modules/mes/mesDeviceVulnerableList.html

+ 328 - 0
db/mysql/add_mes_device_fault_menu.sql

@@ -0,0 +1,328 @@
+-- 设备故障菜单及表:从 mes-MX11-bj 迁入,挂在设备管理 / 设备故障 下
+
+CREATE TABLE IF NOT EXISTS `mes_device_fault_cate` (
+  `id` varchar(64) NOT NULL,
+  `title` varchar(255) DEFAULT NULL COMMENT '名称',
+  `remark` varchar(255) DEFAULT '' COMMENT '备注',
+  `create_date` datetime DEFAULT NULL COMMENT '创建',
+  `update_date` datetime DEFAULT NULL COMMENT '更新时间',
+  `create_by` varchar(64) DEFAULT '',
+  `update_by` varchar(64) DEFAULT '',
+  `status` char(1) DEFAULT '0' COMMENT '状态',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='设备故障分类';
+
+CREATE TABLE IF NOT EXISTS `mes_device_fault_maintain` (
+  `id` varchar(64) NOT NULL,
+  `title` varchar(255) DEFAULT NULL COMMENT '名称',
+  `remark` varchar(255) DEFAULT '' COMMENT '备注',
+  `create_date` datetime DEFAULT NULL COMMENT '创建',
+  `update_date` datetime DEFAULT NULL COMMENT '更新时间',
+  `create_by` varchar(64) DEFAULT '',
+  `update_by` varchar(64) DEFAULT '',
+  `status` char(1) DEFAULT '0' COMMENT '状态',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='设备故障工序';
+
+CREATE TABLE IF NOT EXISTS `mes_device_fault` (
+  `id` varchar(64) NOT NULL,
+  `level` char(100) DEFAULT NULL COMMENT '停台级别',
+  `cate_id` varchar(64) DEFAULT NULL COMMENT '故障分类',
+  `maintain_id` varchar(64) DEFAULT NULL COMMENT '故障工序',
+  `fault_phenomenon` varchar(1000) DEFAULT NULL COMMENT '故障现象',
+  `problem_description` varchar(1000) DEFAULT NULL COMMENT '问题描述',
+  `analysis` varchar(1000) DEFAULT NULL COMMENT '根因分析',
+  `temporary_measures` varchar(1000) DEFAULT NULL COMMENT '临时措施',
+  `eradication_measures` varchar(1000) DEFAULT NULL COMMENT '根除措施',
+  `handle_by` varchar(255) DEFAULT NULL COMMENT '处理人',
+  `start_date` datetime DEFAULT NULL COMMENT '开始时间',
+  `end_date` datetime DEFAULT NULL COMMENT '结束时间',
+  `duration` int(10) unsigned DEFAULT '0' COMMENT '时长(分钟)',
+  `state` char(1) DEFAULT NULL COMMENT '状态 1=整改中 2=已完成',
+  `create_date` datetime DEFAULT NULL COMMENT '创建',
+  `update_date` datetime DEFAULT NULL COMMENT '更新时间',
+  `create_by` varchar(64) DEFAULT '',
+  `update_by` varchar(64) DEFAULT '',
+  `status` char(1) DEFAULT '0' COMMENT '状态',
+  `oprno` varchar(255) DEFAULT NULL COMMENT '工序',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='设备故障记录';
+
+CREATE TABLE IF NOT EXISTS `mes_device_oee` (
+  `id` varchar(64) NOT NULL,
+  `cate_id` varchar(64) DEFAULT NULL COMMENT '阶段',
+  `date` date DEFAULT NULL COMMENT '日期',
+  `plan_num` int(10) DEFAULT NULL COMMENT '计划产量',
+  `today_num` int(10) DEFAULT NULL COMMENT '今日产量',
+  `create_by` varchar(64) DEFAULT '',
+  `create_date` datetime DEFAULT NULL COMMENT '创建时间',
+  `update_by` varchar(64) DEFAULT '',
+  `update_date` datetime DEFAULT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='OEE';
+
+CREATE TABLE IF NOT EXISTS `mes_device_oee_cate` (
+  `id` varchar(64) NOT NULL DEFAULT '',
+  `title` varchar(255) DEFAULT NULL COMMENT '名称',
+  `create_by` varchar(64) DEFAULT '',
+  `create_date` datetime DEFAULT NULL COMMENT '创建时间',
+  `update_by` varchar(64) DEFAULT '',
+  `update_date` datetime DEFAULT NULL COMMENT '更新时间',
+  `status` char(1) DEFAULT '0' COMMENT '状态',
+  `type` char(1) DEFAULT NULL COMMENT '类型',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='OEE工序';
+
+INSERT INTO `js_sys_dict_type` (
+  `id`, `dict_name`, `dict_type`, `is_sys`, `status`,
+  `create_by`, `create_date`, `update_by`, `update_date`, `remarks`
+)
+SELECT 'mesDeviceFaultLevel', '设备故障停台级别', 'mes_device_fault_level', '1', '0',
+  'system', NOW(), 'system', NOW(), '1一级停台 2二级停台 3三级停台'
+FROM DUAL
+WHERE NOT EXISTS (
+  SELECT 1 FROM `js_sys_dict_type` WHERE `dict_type` = 'mes_device_fault_level'
+);
+
+INSERT INTO `js_sys_dict_data` (
+  `dict_code`, `parent_code`, `parent_codes`, `tree_sort`, `tree_sorts`,
+  `tree_leaf`, `tree_level`, `tree_names`, `dict_label`, `dict_value`,
+  `dict_icon`, `dict_type`, `is_sys`, `description`, `css_style`, `css_class`,
+  `status`, `create_by`, `create_date`, `update_by`, `update_date`, `remarks`,
+  `corp_code`, `corp_name`
+)
+SELECT 'mesDeviceFaultLevel1', '0', '0,', 10, '0000000010,',
+  '1', 0, '一级停台', '一级停台', '1',
+  '', 'mes_device_fault_level', '1', '', '', '',
+  '0', 'system', NOW(), 'system', NOW(), '',
+  '0', 'JeeSite'
+FROM DUAL
+WHERE NOT EXISTS (
+  SELECT 1 FROM `js_sys_dict_data` WHERE `dict_type` = 'mes_device_fault_level' AND `dict_value` = '1'
+);
+
+INSERT INTO `js_sys_dict_data` (
+  `dict_code`, `parent_code`, `parent_codes`, `tree_sort`, `tree_sorts`,
+  `tree_leaf`, `tree_level`, `tree_names`, `dict_label`, `dict_value`,
+  `dict_icon`, `dict_type`, `is_sys`, `description`, `css_style`, `css_class`,
+  `status`, `create_by`, `create_date`, `update_by`, `update_date`, `remarks`,
+  `corp_code`, `corp_name`
+)
+SELECT 'mesDeviceFaultLevel2', '0', '0,', 20, '0000000020,',
+  '1', 0, '二级停台', '二级停台', '2',
+  '', 'mes_device_fault_level', '1', '', '', '',
+  '0', 'system', NOW(), 'system', NOW(), '',
+  '0', 'JeeSite'
+FROM DUAL
+WHERE NOT EXISTS (
+  SELECT 1 FROM `js_sys_dict_data` WHERE `dict_type` = 'mes_device_fault_level' AND `dict_value` = '2'
+);
+
+INSERT INTO `js_sys_dict_data` (
+  `dict_code`, `parent_code`, `parent_codes`, `tree_sort`, `tree_sorts`,
+  `tree_leaf`, `tree_level`, `tree_names`, `dict_label`, `dict_value`,
+  `dict_icon`, `dict_type`, `is_sys`, `description`, `css_style`, `css_class`,
+  `status`, `create_by`, `create_date`, `update_by`, `update_date`, `remarks`,
+  `corp_code`, `corp_name`
+)
+SELECT 'mesDeviceFaultLevel3', '0', '0,', 30, '0000000030,',
+  '1', 0, '三级停台', '三级停台', '3',
+  '', 'mes_device_fault_level', '1', '', '', '',
+  '0', 'system', NOW(), 'system', NOW(), '',
+  '0', 'JeeSite'
+FROM DUAL
+WHERE NOT EXISTS (
+  SELECT 1 FROM `js_sys_dict_data` WHERE `dict_type` = 'mes_device_fault_level' AND `dict_value` = '3'
+);
+
+INSERT INTO `js_sys_dict_type` (
+  `id`, `dict_name`, `dict_type`, `is_sys`, `status`,
+  `create_by`, `create_date`, `update_by`, `update_date`, `remarks`
+)
+SELECT 'mesDeviceFaultState', '设备故障记录状态', 'mes_device_fault_state', '1', '0',
+  'system', NOW(), 'system', NOW(), '1整改中 2已完成'
+FROM DUAL
+WHERE NOT EXISTS (
+  SELECT 1 FROM `js_sys_dict_type` WHERE `dict_type` = 'mes_device_fault_state'
+);
+
+INSERT INTO `js_sys_dict_data` (
+  `dict_code`, `parent_code`, `parent_codes`, `tree_sort`, `tree_sorts`,
+  `tree_leaf`, `tree_level`, `tree_names`, `dict_label`, `dict_value`,
+  `dict_icon`, `dict_type`, `is_sys`, `description`, `css_style`, `css_class`,
+  `status`, `create_by`, `create_date`, `update_by`, `update_date`, `remarks`,
+  `corp_code`, `corp_name`
+)
+SELECT 'mesDeviceFaultState1', '0', '0,', 10, '0000000010,',
+  '1', 0, '整改中', '整改中', '1',
+  '', 'mes_device_fault_state', '1', '', '', '',
+  '0', 'system', NOW(), 'system', NOW(), '',
+  '0', 'JeeSite'
+FROM DUAL
+WHERE NOT EXISTS (
+  SELECT 1 FROM `js_sys_dict_data` WHERE `dict_type` = 'mes_device_fault_state' AND `dict_value` = '1'
+);
+
+INSERT INTO `js_sys_dict_data` (
+  `dict_code`, `parent_code`, `parent_codes`, `tree_sort`, `tree_sorts`,
+  `tree_leaf`, `tree_level`, `tree_names`, `dict_label`, `dict_value`,
+  `dict_icon`, `dict_type`, `is_sys`, `description`, `css_style`, `css_class`,
+  `status`, `create_by`, `create_date`, `update_by`, `update_date`, `remarks`,
+  `corp_code`, `corp_name`
+)
+SELECT 'mesDeviceFaultState2', '0', '0,', 20, '0000000020,',
+  '1', 0, '已完成', '已完成', '2',
+  '', 'mes_device_fault_state', '1', '', '', '',
+  '0', 'system', NOW(), 'system', NOW(), '',
+  '0', 'JeeSite'
+FROM DUAL
+WHERE NOT EXISTS (
+  SELECT 1 FROM `js_sys_dict_data` WHERE `dict_type` = 'mes_device_fault_state' AND `dict_value` = '2'
+);
+
+INSERT INTO `js_sys_menu` (
+  `menu_code`, `parent_code`, `parent_codes`, `tree_sort`, `tree_sorts`, `tree_leaf`, `tree_level`,
+  `tree_names`, `menu_name`, `menu_type`, `menu_href`, `menu_target`, `menu_icon`, `menu_color`,
+  `menu_title`, `permission`, `weight`, `is_show`, `sys_code`, `module_codes`, `component`, `params`,
+  `status`, `create_by`, `create_date`, `update_by`, `update_date`, `remarks`
+)
+SELECT
+  'mesDeviceFaultRoot', '1582259848270577664', '0,1582259848270577664,', 445, '0000009170,0000000445,',
+  '0', 1, '设备管理/设备故障', '设备故障', '1', '', '', 'icon-notebook', '', '', '',
+  40, '1', 'default', 'core', NULL, NULL, '0', 'system', NOW(), 'system', NOW(), ''
+FROM DUAL
+WHERE NOT EXISTS (SELECT 1 FROM `js_sys_menu` WHERE `menu_code` = 'mesDeviceFaultRoot');
+
+INSERT INTO `js_sys_menu` (
+  `menu_code`, `parent_code`, `parent_codes`, `tree_sort`, `tree_sorts`, `tree_leaf`, `tree_level`,
+  `tree_names`, `menu_name`, `menu_type`, `menu_href`, `menu_target`, `menu_icon`, `menu_color`,
+  `menu_title`, `permission`, `weight`, `is_show`, `sys_code`, `module_codes`, `component`, `params`,
+  `status`, `create_by`, `create_date`, `update_by`, `update_date`, `remarks`
+)
+SELECT
+  'mesDeviceFaultCate', 'mesDeviceFaultRoot', '0,1582259848270577664,mesDeviceFaultRoot,', 10, '0000009170,0000000445,0000000010,',
+  '1', 2, '设备管理/设备故障/设备故障分类', '设备故障分类', '1', '/mes/mesDeviceFaultCate/list', '', '', '', '',
+  'mes:mesDeviceFaultCate:view,mes:mesDeviceFaultCate:edit',
+  40, '1', 'default', 'core', NULL, NULL, '0', 'system', NOW(), 'system', NOW(), ''
+FROM DUAL
+WHERE NOT EXISTS (SELECT 1 FROM `js_sys_menu` WHERE `menu_code` = 'mesDeviceFaultCate');
+
+INSERT INTO `js_sys_menu` (
+  `menu_code`, `parent_code`, `parent_codes`, `tree_sort`, `tree_sorts`, `tree_leaf`, `tree_level`,
+  `tree_names`, `menu_name`, `menu_type`, `menu_href`, `menu_target`, `menu_icon`, `menu_color`,
+  `menu_title`, `permission`, `weight`, `is_show`, `sys_code`, `module_codes`, `component`, `params`,
+  `status`, `create_by`, `create_date`, `update_by`, `update_date`, `remarks`
+)
+SELECT
+  'mesDeviceFaultMaintain', 'mesDeviceFaultRoot', '0,1582259848270577664,mesDeviceFaultRoot,', 20, '0000009170,0000000445,0000000020,',
+  '1', 2, '设备管理/设备故障/设备故障工序', '设备故障工序', '1', '/mes/mesDeviceFaultMaintain/list', '', '', '', '',
+  'mes:mesDeviceFaultMaintain:view,mes:mesDeviceFaultMaintain:edit',
+  40, '1', 'default', 'core', NULL, NULL, '0', 'system', NOW(), 'system', NOW(), ''
+FROM DUAL
+WHERE NOT EXISTS (SELECT 1 FROM `js_sys_menu` WHERE `menu_code` = 'mesDeviceFaultMaintain');
+
+INSERT INTO `js_sys_menu` (
+  `menu_code`, `parent_code`, `parent_codes`, `tree_sort`, `tree_sorts`, `tree_leaf`, `tree_level`,
+  `tree_names`, `menu_name`, `menu_type`, `menu_href`, `menu_target`, `menu_icon`, `menu_color`,
+  `menu_title`, `permission`, `weight`, `is_show`, `sys_code`, `module_codes`, `component`, `params`,
+  `status`, `create_by`, `create_date`, `update_by`, `update_date`, `remarks`
+)
+SELECT
+  'mesDeviceFaultRecord', 'mesDeviceFaultRoot', '0,1582259848270577664,mesDeviceFaultRoot,', 30, '0000009170,0000000445,0000000030,',
+  '1', 2, '设备管理/设备故障/设备故障记录', '设备故障记录', '1', '/mes/mesDeviceFault/list', '', '', '', '',
+  'mes:mesDeviceFault:view,mes:mesDeviceFault:edit',
+  40, '1', 'default', 'core', NULL, NULL, '0', 'system', NOW(), 'system', NOW(), ''
+FROM DUAL
+WHERE NOT EXISTS (SELECT 1 FROM `js_sys_menu` WHERE `menu_code` = 'mesDeviceFaultRecord');
+
+UPDATE `js_sys_menu`
+SET `parent_code` = 'mesDeviceFaultRoot',
+    `parent_codes` = '0,1582259848270577664,mesDeviceFaultRoot,',
+    `tree_sort` = 40,
+    `tree_sorts` = '0000009170,0000000445,0000000040,',
+    `tree_leaf` = '1',
+    `tree_level` = 2,
+    `tree_names` = '设备管理/设备故障/设备修改记录',
+    `status` = '0',
+    `is_show` = '1',
+    `update_by` = 'system',
+    `update_date` = NOW()
+WHERE `menu_code` = '1775363810180796416';
+
+INSERT INTO `js_sys_menu` (
+  `menu_code`, `parent_code`, `parent_codes`, `tree_sort`, `tree_sorts`, `tree_leaf`, `tree_level`,
+  `tree_names`, `menu_name`, `menu_type`, `menu_href`, `menu_target`, `menu_icon`, `menu_color`,
+  `menu_title`, `permission`, `weight`, `is_show`, `sys_code`, `module_codes`, `component`, `params`,
+  `status`, `create_by`, `create_date`, `update_by`, `update_date`, `remarks`
+)
+SELECT
+  'mesDeviceOee', 'mesDeviceFaultRoot', '0,1582259848270577664,mesDeviceFaultRoot,', 50, '0000009170,0000000445,0000000050,',
+  '1', 2, '设备管理/设备故障/OEE管理', 'OEE管理', '1', '/mes/mesDeviceOee/list', '', '', '', '',
+  'mes:mesDeviceOee:view,mes:mesDeviceOee:edit',
+  40, '1', 'default', 'core', NULL, NULL, '0', 'system', NOW(), 'system', NOW(), ''
+FROM DUAL
+WHERE NOT EXISTS (SELECT 1 FROM `js_sys_menu` WHERE `menu_code` = 'mesDeviceOee');
+
+INSERT INTO `js_sys_menu` (
+  `menu_code`, `parent_code`, `parent_codes`, `tree_sort`, `tree_sorts`, `tree_leaf`, `tree_level`,
+  `tree_names`, `menu_name`, `menu_type`, `menu_href`, `menu_target`, `menu_icon`, `menu_color`,
+  `menu_title`, `permission`, `weight`, `is_show`, `sys_code`, `module_codes`, `component`, `params`,
+  `status`, `create_by`, `create_date`, `update_by`, `update_date`, `remarks`
+)
+SELECT
+  'mesDeviceOeeCate', 'mesDeviceFaultRoot', '0,1582259848270577664,mesDeviceFaultRoot,', 60, '0000009170,0000000445,0000000060,',
+  '1', 2, '设备管理/设备故障/OEE工序管理', 'OEE工序管理', '1', '/mes/mesDeviceOeeCate/list', '', '', '', '',
+  'mes:mesDeviceOeeCate:view,mes:mesDeviceOeeCate:edit',
+  40, '1', 'default', 'core', NULL, NULL, '0', 'system', NOW(), 'system', NOW(), ''
+FROM DUAL
+WHERE NOT EXISTS (SELECT 1 FROM `js_sys_menu` WHERE `menu_code` = 'mesDeviceOeeCate');
+
+CREATE TABLE IF NOT EXISTS `mes_device_vulnerable_list` (
+  `id` varchar(64) NOT NULL,
+  `oprno` varchar(20) DEFAULT NULL COMMENT '工位编号',
+  `material_id` varchar(64) DEFAULT NULL COMMENT '物料编号',
+  `oprno_name` varchar(100) DEFAULT NULL COMMENT '工位名称',
+  `device_name` varchar(255) DEFAULT NULL COMMENT '设备名称',
+  `model` varchar(255) DEFAULT NULL COMMENT '型号',
+  `brand` varchar(100) DEFAULT NULL COMMENT '品牌',
+  `min_inventory` bigint(20) DEFAULT NULL COMMENT '最小库存',
+  `max_inventory` bigint(20) DEFAULT NULL COMMENT '最大库存',
+  `unit` varchar(20) DEFAULT NULL COMMENT '单位',
+  `purchase_cycle` varchar(64) DEFAULT NULL COMMENT '采购周期',
+  `use_cycle` varchar(100) DEFAULT NULL COMMENT '使用周期',
+  `price` varchar(64) DEFAULT NULL COMMENT '单价',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='产线设备易损件清单';
+
+INSERT INTO `js_sys_menu` (
+  `menu_code`, `parent_code`, `parent_codes`, `tree_sort`, `tree_sorts`, `tree_leaf`, `tree_level`,
+  `tree_names`, `menu_name`, `menu_type`, `menu_href`, `menu_target`, `menu_icon`, `menu_color`,
+  `menu_title`, `permission`, `weight`, `is_show`, `sys_code`, `module_codes`, `component`, `params`,
+  `status`, `create_by`, `create_date`, `update_by`, `update_date`, `remarks`
+)
+SELECT
+  'mesDeviceVulnerable', 'mesDeviceFaultRoot', '0,1582259848270577664,mesDeviceFaultRoot,', 70, '0000009170,0000000445,0000000070,',
+  '1', 2, '设备管理/设备故障/产线设备易损件清单', '产线设备易损件清单', '1', '/mes/mesDeviceVulnerable/list', '', '', '', '',
+  'mes:mesDeviceVulnerable:view,mes:mesDeviceVulnerable:edit',
+  40, '1', 'default', 'core', NULL, NULL, '0', 'system', NOW(), 'system', NOW(), ''
+FROM DUAL
+WHERE NOT EXISTS (SELECT 1 FROM `js_sys_menu` WHERE `menu_code` = 'mesDeviceVulnerable');
+
+INSERT INTO `js_sys_role_menu` (`role_code`, `menu_code`)
+SELECT r.role_code, m.menu_code
+FROM `js_sys_role_menu` r
+JOIN (
+  SELECT 'mesDeviceFaultRoot' AS menu_code
+  UNION ALL SELECT 'mesDeviceFaultCate'
+  UNION ALL SELECT 'mesDeviceFaultMaintain'
+  UNION ALL SELECT 'mesDeviceFaultRecord'
+  UNION ALL SELECT '1775363810180796416'
+  UNION ALL SELECT 'mesDeviceOee'
+  UNION ALL SELECT 'mesDeviceOeeCate'
+  UNION ALL SELECT 'mesDeviceVulnerable'
+) m
+WHERE r.menu_code = '1582259848270577664'
+AND NOT EXISTS (
+  SELECT 1 FROM `js_sys_role_menu` x
+  WHERE x.role_code = r.role_code AND x.menu_code = m.menu_code
+);

+ 22 - 0
db/mysql/add_mes_device_prevent_task_batch.sql

@@ -0,0 +1,22 @@
+-- 维护计划按批次归组:同一份周期计划共用 batch_id,列表按批次展示一级,展开看各期任务
+ALTER TABLE `mes_device_prevent_task`
+  ADD COLUMN `batch_id` varchar(64) DEFAULT NULL COMMENT '计划批次' AFTER `prevent_id`;
+
+UPDATE `mes_device_prevent_task` t
+JOIN (
+  SELECT MIN(id) AS batch_id, prevent_id, device_id, IFNULL(user_code, '') AS user_code, create_date
+  FROM `mes_device_prevent_task`
+  GROUP BY prevent_id, device_id, IFNULL(user_code, ''), create_date
+) g ON t.prevent_id <=> g.prevent_id
+   AND t.device_id <=> g.device_id
+   AND IFNULL(t.user_code, '') = g.user_code
+   AND t.create_date <=> g.create_date
+SET t.batch_id = g.batch_id
+WHERE t.batch_id IS NULL OR t.batch_id = '';
+
+UPDATE `mes_device_prevent_task`
+SET `batch_id` = `id`
+WHERE `batch_id` IS NULL OR `batch_id` = '';
+
+ALTER TABLE `mes_device_prevent_task`
+  ADD INDEX `idx_prevent_task_batch_id` (`batch_id`);

+ 8 - 0
db/mysql/rename_prevent_task_record_menu.sql

@@ -0,0 +1,8 @@
+-- 预防性维护:我的维护计划改为预防性维护记录(菜单名称)
+UPDATE `js_sys_menu`
+SET `menu_name` = '预防性维护记录',
+    `tree_names` = REPLACE(`tree_names`, '我的维护计划', '预防性维护记录'),
+    `update_by` = 'system',
+    `update_date` = NOW()
+WHERE `menu_code` = '1693424373231202304'
+   OR `menu_href` = '/mes/mesDevicePreventTask/mylist';

+ 16 - 0
src/main/java/com/jeesite/modules/mes/dao/MesDeviceFaultCateDao.java

@@ -0,0 +1,16 @@
+package com.jeesite.modules.mes.dao;
+
+import com.jeesite.common.dao.CrudDao;
+import com.jeesite.common.mybatis.annotation.MyBatisDao;
+import com.jeesite.modules.mes.entity.MesDeviceFaultCate;
+
+/**
+ * 设备故障分类DAO接口
+ * @author hzd
+ * @version 2024-07-23
+ */
+@MyBatisDao
+public interface MesDeviceFaultCateDao extends CrudDao<MesDeviceFaultCate> {
+       MesDeviceFaultCate findByTitle(String title);
+	
+}

+ 15 - 0
src/main/java/com/jeesite/modules/mes/dao/MesDeviceFaultDao.java

@@ -0,0 +1,15 @@
+package com.jeesite.modules.mes.dao;
+
+import com.jeesite.common.dao.CrudDao;
+import com.jeesite.common.mybatis.annotation.MyBatisDao;
+import com.jeesite.modules.mes.entity.MesDeviceFault;
+
+/**
+ * 设备故障记录DAO接口
+ * @author hzd
+ * @version 2024-07-23
+ */
+@MyBatisDao
+public interface MesDeviceFaultDao extends CrudDao<MesDeviceFault> {
+	
+}

+ 15 - 0
src/main/java/com/jeesite/modules/mes/dao/MesDeviceFaultMaintainDao.java

@@ -0,0 +1,15 @@
+package com.jeesite.modules.mes.dao;
+
+import com.jeesite.common.dao.CrudDao;
+import com.jeesite.common.mybatis.annotation.MyBatisDao;
+import com.jeesite.modules.mes.entity.MesDeviceFaultMaintain;
+
+/**
+ * 设备故障维护DAO接口
+ * @author mes
+ * @version 2024-07-31
+ */
+@MyBatisDao
+public interface MesDeviceFaultMaintainDao extends CrudDao<MesDeviceFaultMaintain> {
+    MesDeviceFaultMaintain findByTitle(String title);
+}

+ 15 - 0
src/main/java/com/jeesite/modules/mes/dao/MesDeviceOeeCateDao.java

@@ -0,0 +1,15 @@
+package com.jeesite.modules.mes.dao;
+
+import com.jeesite.common.dao.CrudDao;
+import com.jeesite.common.mybatis.annotation.MyBatisDao;
+import com.jeesite.modules.mes.entity.MesDeviceOeeCate;
+
+/**
+ * 设备OEE阶段DAO接口
+ * @author hzd
+ * @version 2024-08-23
+ */
+@MyBatisDao
+public interface MesDeviceOeeCateDao extends CrudDao<MesDeviceOeeCate> {
+	
+}

+ 15 - 0
src/main/java/com/jeesite/modules/mes/dao/MesDeviceOeeDao.java

@@ -0,0 +1,15 @@
+package com.jeesite.modules.mes.dao;
+
+import com.jeesite.common.dao.CrudDao;
+import com.jeesite.common.mybatis.annotation.MyBatisDao;
+import com.jeesite.modules.mes.entity.MesDeviceOee;
+
+/**
+ * OEEDAO接口
+ * @author mes
+ * @version 2024-08-02
+ */
+@MyBatisDao
+public interface MesDeviceOeeDao extends CrudDao<MesDeviceOee> {
+    MesDeviceOee findByDateAndtitle(MesDeviceOee mesDeviceOee);
+}

+ 6 - 1
src/main/java/com/jeesite/modules/mes/dao/MesDevicePreventTaskDao.java

@@ -4,6 +4,8 @@ import com.jeesite.common.dao.CrudDao;
 import com.jeesite.common.mybatis.annotation.MyBatisDao;
 import com.jeesite.modules.mes.entity.MesDevicePreventTask;
 
+import java.util.List;
+
 /**
  * 预防性维修计划DAO接口
  * @author hzd
@@ -11,5 +13,8 @@ import com.jeesite.modules.mes.entity.MesDevicePreventTask;
  */
 @MyBatisDao
 public interface MesDevicePreventTaskDao extends CrudDao<MesDevicePreventTask> {
-	
+
+	List<MesDevicePreventTask> findPlanList(MesDevicePreventTask mesDevicePreventTask);
+
+	long findPlanCount(MesDevicePreventTask mesDevicePreventTask);
 }

+ 15 - 0
src/main/java/com/jeesite/modules/mes/dao/MesDeviceVulnerableDao.java

@@ -0,0 +1,15 @@
+package com.jeesite.modules.mes.dao;
+
+import com.jeesite.common.dao.CrudDao;
+import com.jeesite.common.mybatis.annotation.MyBatisDao;
+import com.jeesite.modules.mes.entity.MesDeviceVulnerable;
+
+/**
+ * mes_device_vulnerable_listDAO接口
+ * @author mes
+ * @version 2024-08-05
+ */
+@MyBatisDao
+public interface MesDeviceVulnerableDao extends CrudDao<MesDeviceVulnerable> {
+	
+}

+ 274 - 0
src/main/java/com/jeesite/modules/mes/entity/MesDeviceFault.java

@@ -0,0 +1,274 @@
+package com.jeesite.modules.mes.entity;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.jeesite.common.entity.DataEntity;
+import com.jeesite.common.mybatis.annotation.Column;
+import com.jeesite.common.mybatis.annotation.JoinTable;
+import com.jeesite.common.mybatis.annotation.JoinTable.Type;
+import com.jeesite.common.mybatis.annotation.Table;
+import com.jeesite.common.mybatis.mapper.query.QueryType;
+import com.jeesite.common.utils.excel.annotation.ExcelField;
+import com.jeesite.common.utils.excel.annotation.ExcelField.Align;
+import com.jeesite.common.utils.excel.annotation.ExcelFields;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import java.util.Date;
+
+/**
+ * 设备故障记录Entity
+ * @author hzd
+ * @version 2024-07-23
+ */
+@Table(name="mes_device_fault", alias="a", label="设备故障记录信息", columns={
+		@Column(name="id", attrName="id", label="id", isPK=true),
+		@Column(name="oprno", attrName="oprno", label="工序",queryType=QueryType.LIKE),
+		@Column(name="level", attrName="level", label="停台级别"),
+		@Column(name="cate_id", attrName="cateId", label="故障分类"),
+		@Column(name="maintain_id", attrName="maintainId", label="故障工序"),
+		@Column(name="fault_phenomenon", attrName="faultPhenomenon", label="故障现象",queryType=QueryType.LIKE),
+		@Column(name="problem_description", attrName="problemDescription", label="问题描述",queryType=QueryType.LIKE),
+		@Column(name="analysis", attrName="analysis", label="根因分析",queryType=QueryType.LIKE),
+		@Column(name="temporary_measures", attrName="temporaryMeasures", label="临时措施",queryType=QueryType.LIKE),
+		@Column(name="eradication_measures", attrName="eradicationMeasures", label="根除措施",queryType=QueryType.LIKE),
+		@Column(name="handle_by", attrName="handleBy", label="处理人",queryType=QueryType.LIKE),
+		@Column(name="start_date", attrName="startDate", label="开始时间"),
+		@Column(name="end_date", attrName="endDate", label="结束时间", isUpdateForce=true),
+		@Column(name="duration", attrName="duration", label="时长", comment="时长(分钟)"),
+		@Column(name="state", attrName="state", label="状态"),
+		@Column(name="create_date", attrName="createDate", label="创建时间", isUpdate=false, isQuery=false, isUpdateForce=true),
+		@Column(name="update_date", attrName="updateDate", label="更新时间", isQuery=false, isUpdateForce=true),
+		@Column(name="create_by", attrName="createBy", label="create_by", isUpdate=false, isQuery=false),
+		@Column(name="update_by", attrName="updateBy", label="update_by", isQuery=false),
+		@Column(name="status", attrName="status", label="状态", isUpdate=false, isQuery=true),
+	}, joinTable={
+		@JoinTable(type=Type.LEFT_JOIN, entity=MesDeviceFaultCate.class, attrName="this", alias="b",
+				on="a.cate_id = b.id", columns={
+				@Column(name="title", attrName="cateTitle",label="故障分类" ),
+		}),
+		@JoinTable(type=Type.LEFT_JOIN, entity=MesDeviceFaultMaintain.class, attrName="this", alias="c",
+				on="a.maintain_id = c.id", columns={
+				@Column(name="title", attrName="maintainTitle",label="故障工序" ),
+		}),
+
+	}, orderBy="a.update_date DESC"
+)
+public class MesDeviceFault extends DataEntity<MesDeviceFault> {
+	
+	private static final long serialVersionUID = 1L;
+	private String oprno;
+	private String level;		// 停台级别
+	private String cateId;		// 故障分类
+	private String maintainId;		// 故障工序
+	private String faultPhenomenon;		// 故障现象
+	private String problemDescription;		// 问题描述
+	private String analysis;		// 根因分析
+	private String temporaryMeasures;		// 临时措施
+	private String eradicationMeasures;		// 根除措施
+	private String handleBy;		// 处理人
+	private Date startDate;		// 开始时间
+	private Date endDate;		// 结束时间
+	private Integer duration;		// 时长(分钟)
+	private String state;		// 状态 1=整改中 2=已完成
+	private String cateTitle;
+	private String maintainTitle;
+
+	@ExcelFields({
+//		@ExcelField(title="工序", attrName="oprno", align=Align.CENTER, sort=10),
+		@ExcelField(title="故障工序", attrName="maintainTitle", align=Align.CENTER, sort=10),
+		@ExcelField(title="停台级别", attrName="level", dictType="mes_device_fault_level", align=Align.CENTER, sort=20),
+		@ExcelField(title="故障分类", attrName="cateTitle", align=Align.CENTER, sort=30),
+		@ExcelField(title="故障现象", attrName="faultPhenomenon", align=Align.CENTER, sort=40),
+		@ExcelField(title="问题描述", attrName="problemDescription", align=Align.CENTER, sort=50),
+		@ExcelField(title="根因分析", attrName="analysis", align=Align.CENTER, sort=60),
+		@ExcelField(title="临时措施", attrName="temporaryMeasures", align=Align.CENTER, sort=70),
+		@ExcelField(title="根除措施", attrName="eradicationMeasures", align=Align.CENTER, sort=80),
+		@ExcelField(title="处理人", attrName="handleBy", align=Align.CENTER, sort=90),
+		@ExcelField(title="开始时间", attrName="startDate", align=Align.CENTER, sort=100, dataFormat="yyyy-MM-dd hh:mm"),
+		@ExcelField(title="结束时间", attrName="endDate", align=Align.CENTER, sort=110, dataFormat="yyyy-MM-dd hh:mm"),
+		@ExcelField(title="时长", attrName="duration", align=Align.CENTER, sort=120),
+		@ExcelField(title="状态", attrName="state",dictType="mes_device_fault_state", align=Align.CENTER, sort=130),
+		@ExcelField(title="创建时间", attrName="createDate", align=Align.CENTER, sort=140),
+	})
+	public MesDeviceFault() {
+		this(null);
+	}
+
+	public MesDeviceFault(String id){
+		super(id);
+	}
+	
+	@Size(min=0, max=100, message="停台级别长度不能超过 100 个字符")
+	public String getLevel() {
+		return level;
+	}
+
+	public void setLevel(String level) {
+		this.level = level;
+	}
+
+	@Size(min=0, max=64, message="故障分类长度不能超过 64 个字符")
+	public String getCateId() {
+		return cateId;
+	}
+
+	public void setCateId(String cateId) {
+		this.cateId = cateId;
+	}
+	
+	@Size(min=0, max=255, message="故障现象长度不能超过 255 个字符")
+	public String getFaultPhenomenon() {
+		return faultPhenomenon;
+	}
+
+	public void setFaultPhenomenon(String faultPhenomenon) {
+		this.faultPhenomenon = faultPhenomenon;
+	}
+	
+	@Size(min=0, max=255, message="问题描述长度不能超过 255 个字符")
+	public String getProblemDescription() {
+		return problemDescription;
+	}
+
+	public void setProblemDescription(String problemDescription) {
+		this.problemDescription = problemDescription;
+	}
+	
+	@Size(min=0, max=255, message="根因分析长度不能超过 255 个字符")
+	public String getAnalysis() {
+		return analysis;
+	}
+
+	public void setAnalysis(String analysis) {
+		this.analysis = analysis;
+	}
+	
+	@Size(min=0, max=255, message="临时措施长度不能超过 255 个字符")
+	public String getTemporaryMeasures() {
+		return temporaryMeasures;
+	}
+
+	public void setTemporaryMeasures(String temporaryMeasures) {
+		this.temporaryMeasures = temporaryMeasures;
+	}
+	
+	@Size(min=0, max=255, message="根除措施长度不能超过 255 个字符")
+	public String getEradicationMeasures() {
+		return eradicationMeasures;
+	}
+
+	public void setEradicationMeasures(String eradicationMeasures) {
+		this.eradicationMeasures = eradicationMeasures;
+	}
+	
+	@Size(min=0, max=255, message="处理人长度不能超过 255 个字符")
+	public String getHandleBy() {
+		return handleBy;
+	}
+
+	public void setHandleBy(String handleBy) {
+		this.handleBy = handleBy;
+	}
+	
+	@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+	@NotNull(message="开始时间不能为空")
+	public Date getStartDate() {
+		return startDate;
+	}
+
+	public void setStartDate(Date startDate) {
+		this.startDate = startDate;
+	}
+	
+	@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+	public Date getEndDate() {
+		return endDate;
+	}
+
+	public void setEndDate(Date endDate) {
+		this.endDate = endDate;
+	}
+
+	public Integer getDuration() {
+		return duration;
+	}
+
+	public void setDuration(Integer duration) {
+		this.duration = duration;
+	}
+	
+	@NotBlank(message="状态 1=整改中 2=已完成不能为空")
+	@Size(min=0, max=1, message="状态长度不能超过 1 个字符")
+	public String getState() {
+		return state;
+	}
+
+	public void setState(String state) {
+		this.state = state;
+	}
+	
+	public Date getStartDate_gte() {
+		return sqlMap.getWhere().getValue("start_date", QueryType.GTE);
+	}
+
+	public void setStartDate_gte(Date startDate) {
+		sqlMap.getWhere().and("start_date", QueryType.GTE, startDate);
+	}
+	
+	public Date getStartDate_lte() {
+		return sqlMap.getWhere().getValue("start_date", QueryType.LTE);
+	}
+
+	public void setStartDate_lte(Date startDate) {
+		sqlMap.getWhere().and("start_date", QueryType.LTE, startDate);
+	}
+	
+	public Date getEndDate_gte() {
+		return sqlMap.getWhere().getValue("end_date", QueryType.GTE);
+	}
+
+	public void setEndDate_gte(Date endDate) {
+		sqlMap.getWhere().and("end_date", QueryType.GTE, endDate);
+	}
+	
+	public Date getEndDate_lte() {
+		return sqlMap.getWhere().getValue("end_date", QueryType.LTE);
+	}
+
+	public void setEndDate_lte(Date endDate) {
+		sqlMap.getWhere().and("end_date", QueryType.LTE, endDate);
+	}
+
+	public String getOprno() {
+		return oprno;
+	}
+
+	public void setOprno(String oprno) {
+		this.oprno = oprno;
+	}
+
+	public String getCateTitle() {
+		return cateTitle;
+	}
+
+	public void setCateTitle(String cateTitle) {
+		this.cateTitle = cateTitle;
+	}
+
+	public String getMaintainId() {
+		return maintainId;
+	}
+
+	public void setMaintainId(String maintainId) {
+		this.maintainId = maintainId;
+	}
+
+	public String getMaintainTitle() {
+		return maintainTitle;
+	}
+
+	public void setMaintainTitle(String maintainTitle) {
+		this.maintainTitle = maintainTitle;
+	}
+}

+ 60 - 0
src/main/java/com/jeesite/modules/mes/entity/MesDeviceFaultCate.java

@@ -0,0 +1,60 @@
+package com.jeesite.modules.mes.entity;
+
+import com.jeesite.common.entity.DataEntity;
+import com.jeesite.common.mybatis.annotation.Column;
+import com.jeesite.common.mybatis.annotation.Table;
+import com.jeesite.common.mybatis.mapper.query.QueryType;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+
+/**
+ * 设备故障分类Entity
+ * @author hzd
+ * @version 2024-07-23
+ */
+@Table(name="mes_device_fault_cate", alias="a", label="设备故障分类信息", columns={
+		@Column(name="id", attrName="id", label="id", isPK=true),
+		@Column(name="title", attrName="title", label="名称", queryType=QueryType.LIKE),
+		@Column(name="remark", attrName="remark", label="备注"),
+		@Column(name="status", attrName="status", label="状态", isUpdate=false),
+		@Column(name="create_date", attrName="createDate", label="创建", isUpdate=false, isQuery=false, isUpdateForce=true),
+		@Column(name="update_date", attrName="updateDate", label="更新时间", isQuery=false, isUpdateForce=true),
+		@Column(name="create_by", attrName="createBy", label="create_by", isUpdate=false, isQuery=false),
+		@Column(name="update_by", attrName="updateBy", label="update_by", isQuery=false),
+	}, orderBy="a.update_date DESC"
+)
+public class MesDeviceFaultCate extends DataEntity<MesDeviceFaultCate> {
+	
+	private static final long serialVersionUID = 1L;
+	private String title;		// 名称
+	private String remark;		// 备注
+
+	public MesDeviceFaultCate() {
+		this(null);
+	}
+	
+	public MesDeviceFaultCate(String id){
+		super(id);
+	}
+	
+	@NotBlank(message="名称不能为空")
+	@Size(min=0, max=255, message="名称长度不能超过 255 个字符")
+	public String getTitle() {
+		return title;
+	}
+
+	public void setTitle(String title) {
+		this.title = title;
+	}
+	
+	@Size(min=0, max=255, message="备注长度不能超过 255 个字符")
+	public String getRemark() {
+		return remark;
+	}
+
+	public void setRemark(String remark) {
+		this.remark = remark;
+	}
+	
+}

+ 103 - 0
src/main/java/com/jeesite/modules/mes/entity/MesDeviceFaultMaintain.java

@@ -0,0 +1,103 @@
+package com.jeesite.modules.mes.entity;
+
+import com.jeesite.common.entity.DataEntity;
+import com.jeesite.common.mybatis.annotation.Column;
+import com.jeesite.common.mybatis.annotation.Table;
+import com.jeesite.common.mybatis.mapper.query.QueryType;
+import com.jeesite.common.utils.excel.annotation.ExcelField;
+import com.jeesite.common.utils.excel.annotation.ExcelField.Align;
+import com.jeesite.common.utils.excel.annotation.ExcelFields;
+
+import javax.validation.constraints.Size;
+import java.util.Date;
+
+/**
+ * 设备故障维护Entity
+ * @author mes
+ * @version 2024-07-31
+ */
+@Table(name="mes_device_fault_maintain", alias="a", label="设备故障维护信息", columns={
+		@Column(name="id", attrName="id", label="id", isPK=true),
+		@Column(name="title", attrName="title", label="名称", queryType=QueryType.LIKE),
+		@Column(name="remark", attrName="remark", label="备注", queryType=QueryType.LIKE),
+		@Column(name="create_date", attrName="createDate", label="创建时间", isUpdateForce=true),
+		@Column(name="update_date", attrName="updateDate", label="更新时间", isUpdateForce=true),
+		@Column(name="create_by", attrName="createBy", label="create_by"),
+		@Column(name="update_by", attrName="updateBy", label="update_by"),
+		@Column(name="status", attrName="status", label="状态"),
+	}, orderBy="a.update_date DESC"
+)
+public class MesDeviceFaultMaintain extends DataEntity<MesDeviceFaultMaintain> {
+	
+	private static final long serialVersionUID = 1L;
+	private String title;		// 名称
+	private String remark;		// 备注
+
+	@ExcelFields({
+		@ExcelField(title="名称", attrName="title", align=Align.CENTER, sort=20),
+		@ExcelField(title="备注", attrName="remark", align=Align.CENTER, sort=30),
+//		@ExcelField(title="创建时间", attrName="createDate", align=Align.CENTER, sort=40, dataFormat="yyyy-MM-dd hh:mm"),
+		@ExcelField(title="更新时间", attrName="updateDate", align=Align.CENTER, sort=50, dataFormat="yyyy-MM-dd hh:mm"),
+//		@ExcelField(title="create_by", attrName="createBy", align=Align.CENTER, sort=60),
+//		@ExcelField(title="update_by", attrName="updateBy", align=Align.CENTER, sort=70),
+		@ExcelField(title="状态", attrName="status", dictType="sys_search_status", align=Align.CENTER, sort=80),
+	})
+	public MesDeviceFaultMaintain() {
+		this(null);
+	}
+	
+	public MesDeviceFaultMaintain(String id){
+		super(id);
+	}
+	
+	@Size(min=0, max=255, message="名称长度不能超过 255 个字符")
+	public String getTitle() {
+		return title;
+	}
+
+	public void setTitle(String title) {
+		this.title = title;
+	}
+	
+	@Size(min=0, max=255, message="备注长度不能超过 255 个字符")
+	public String getRemark() {
+		return remark;
+	}
+
+	public void setRemark(String remark) {
+		this.remark = remark;
+	}
+	
+	public Date getCreateDate_gte() {
+		return sqlMap.getWhere().getValue("create_date", QueryType.GTE);
+	}
+
+	public void setCreateDate_gte(Date createDate) {
+		sqlMap.getWhere().and("create_date", QueryType.GTE, createDate);
+	}
+	
+	public Date getCreateDate_lte() {
+		return sqlMap.getWhere().getValue("create_date", QueryType.LTE);
+	}
+
+	public void setCreateDate_lte(Date createDate) {
+		sqlMap.getWhere().and("create_date", QueryType.LTE, createDate);
+	}
+	
+	public Date getUpdateDate_gte() {
+		return sqlMap.getWhere().getValue("update_date", QueryType.GTE);
+	}
+
+	public void setUpdateDate_gte(Date updateDate) {
+		sqlMap.getWhere().and("update_date", QueryType.GTE, updateDate);
+	}
+	
+	public Date getUpdateDate_lte() {
+		return sqlMap.getWhere().getValue("update_date", QueryType.LTE);
+	}
+
+	public void setUpdateDate_lte(Date updateDate) {
+		sqlMap.getWhere().and("update_date", QueryType.LTE, updateDate);
+	}
+	
+}

+ 1 - 0
src/main/java/com/jeesite/modules/mes/entity/MesDeviceForm.java

@@ -32,6 +32,7 @@ import java.util.List;
 		@JoinTable(type= JoinTable.Type.LEFT_JOIN, entity=MesDevice.class, attrName="device", alias="b",
 				on="a.device_id = b.tree_code", columns={
 				@Column(name="tree_name", label="设备名称", isQuery=false),
+				@Column(name="sn", attrName="sn", label="唯一编号", isQuery=false),
 		}),
 
 },  orderBy="a.update_date DESC"

+ 120 - 0
src/main/java/com/jeesite/modules/mes/entity/MesDeviceOee.java

@@ -0,0 +1,120 @@
+package com.jeesite.modules.mes.entity;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.jeesite.common.entity.DataEntity;
+import com.jeesite.common.mybatis.annotation.Column;
+import com.jeesite.common.mybatis.annotation.JoinTable;
+import com.jeesite.common.mybatis.annotation.JoinTable.Type;
+import com.jeesite.common.mybatis.annotation.Table;
+import com.jeesite.common.utils.excel.annotation.ExcelField;
+import com.jeesite.common.utils.excel.annotation.ExcelField.Align;
+import com.jeesite.common.utils.excel.annotation.ExcelFields;
+
+import javax.validation.constraints.NotNull;
+import java.util.Date;
+
+/**
+ * OEEEntity
+ * @author mes
+ * @version 2024-08-02
+ */
+@Table(name="mes_device_oee", alias="a", label="OEE信息", columns={
+		@Column(name="id", attrName="id", label="id", isPK=true),
+		@Column(name="cate_id", attrName="cateId", label="阶段id"),
+		@Column(name="date", attrName="date", label="日期"),
+		@Column(name="plan_num", attrName="planNum", label="计划产量", isUpdateForce=true),
+		@Column(name="today_num", attrName="todayNum", label="当日产量", isUpdateForce=true),
+		@Column(name="create_by", attrName="createBy", label="create_by", isUpdate=false, isQuery=false),
+		@Column(name="create_date", attrName="createDate", label="创建时间", isUpdate=false, isQuery=false, isUpdateForce=true),
+		@Column(name="update_by", attrName="updateBy", label="update_by", isQuery=false),
+		@Column(name="update_date", attrName="updateDate", label="更新时间", isQuery=false, isUpdateForce=true),
+	},joinTable={
+		@JoinTable(type=Type.LEFT_JOIN, entity=MesDeviceOeeCate.class, attrName="this", alias="b",
+				on="a.cate_id = b.id", columns={
+				@Column(name="title", attrName="cateTitle",label="阶段" ),
+		}),
+},orderBy="a.update_date DESC"
+)
+public class MesDeviceOee extends DataEntity<MesDeviceOee> {
+	
+	private static final long serialVersionUID = 1L;
+	private String cateId;		// 故障工序id
+	private Date date;		// 日期
+	private Integer planNum;		// 昨日晚班数
+	private Integer todayNum;		// 今日白班数
+	private String cateTitle;		//工序名称
+	private Date sdate;
+	private Date edate;
+	@ExcelFields({
+		@ExcelField(title="阶段", attrName="cateTitle", align=Align.CENTER, sort=20),
+		@ExcelField(title="日期", attrName="date", align=Align.CENTER, sort=30, dataFormat="yyyy-MM-dd"),
+		@ExcelField(title="计划产量", attrName="planNum", align=Align.CENTER, sort=40),
+		@ExcelField(title="当日产量", attrName="todayNum", align=Align.CENTER, sort=50),
+		@ExcelField(title="创建时间", attrName="createDate", align=Align.CENTER, sort=70),
+	})
+	public MesDeviceOee() {
+		this(null);
+	}
+	
+	public MesDeviceOee(String id){
+		super(id);
+	}
+	
+	@JsonFormat(pattern = "yyyy-MM-dd")
+	@NotNull(message="日期不能为空")
+	public Date getDate() {
+		return date;
+	}
+
+	public void setDate(Date date) {
+		this.date = date;
+	}
+
+	public String getCateId() {
+		return cateId;
+	}
+
+	public void setCateId(String cateId) {
+		this.cateId = cateId;
+	}
+
+	public Integer getPlanNum() {
+		return planNum;
+	}
+
+	public void setPlanNum(Integer planNum) {
+		this.planNum = planNum;
+	}
+
+	public Integer getTodayNum() {
+		return todayNum;
+	}
+
+	public void setTodayNum(Integer todayNum) {
+		this.todayNum = todayNum;
+	}
+
+	public String getCateTitle() {
+		return cateTitle;
+	}
+
+	public void setCateTitle(String cateTitle) {
+		this.cateTitle = cateTitle;
+	}
+
+	public Date getSdate() {
+		return sdate;
+	}
+
+	public void setSdate(Date sdate) {
+		this.sdate = sdate;
+	}
+
+	public Date getEdate() {
+		return edate;
+	}
+
+	public void setEdate(Date edate) {
+		this.edate = edate;
+	}
+}

+ 57 - 0
src/main/java/com/jeesite/modules/mes/entity/MesDeviceOeeCate.java

@@ -0,0 +1,57 @@
+package com.jeesite.modules.mes.entity;
+
+import com.jeesite.common.entity.DataEntity;
+import com.jeesite.common.mybatis.annotation.Column;
+import com.jeesite.common.mybatis.annotation.Table;
+import com.jeesite.common.mybatis.mapper.query.QueryType;
+
+import javax.validation.constraints.Size;
+
+/**
+ * 设备OEE阶段Entity
+ * @author hzd
+ * @version 2024-08-23
+ */
+@Table(name="mes_device_oee_cate", alias="a", label="设备OEE阶段信息", columns={
+		@Column(name="id", attrName="id", label="id", isPK=true),
+		@Column(name="title", attrName="title", label="名称", queryType=QueryType.LIKE),
+		@Column(name="create_by", attrName="createBy", label="create_by", isUpdate=false, isQuery=false),
+		@Column(name="create_date", attrName="createDate", label="创建时间", isUpdate=false, isQuery=false, isUpdateForce=true),
+		@Column(name="update_by", attrName="updateBy", label="update_by", isQuery=false),
+		@Column(name="update_date", attrName="updateDate", label="更新时间", isQuery=false, isUpdateForce=true),
+		@Column(name="status", attrName="status", label="状态", isUpdate=false),
+		@Column(name="type", attrName="type", label="类型"),
+	}, orderBy="a.id ASC"
+)
+public class MesDeviceOeeCate extends DataEntity<MesDeviceOeeCate> {
+	
+	private static final long serialVersionUID = 1L;
+	private String title;		// 名称
+
+	private String type;
+
+	public MesDeviceOeeCate() {
+		this(null);
+	}
+	
+	public MesDeviceOeeCate(String id){
+		super(id);
+	}
+	
+	@Size(min=0, max=255, message="名称长度不能超过 255 个字符")
+	public String getTitle() {
+		return title;
+	}
+
+	public void setTitle(String title) {
+		this.title = title;
+	}
+
+	public String getType() {
+		return type;
+	}
+
+	public void setType(String type) {
+		this.type = type;
+	}
+}

+ 31 - 0
src/main/java/com/jeesite/modules/mes/entity/MesDevicePreventTask.java

@@ -26,6 +26,7 @@ import java.util.List;
 @Table(name="mes_device_prevent_task", alias="a", label="预防性维修计划信息", columns={
 		@Column(name="id", attrName="id", label="id", isPK=true),
 		@Column(name="prevent_id", attrName="preventId", label="任务清单"),
+		@Column(name="batch_id", attrName="batchId", label="计划批次"),
 		@Column(name="user_code", attrName="userCode", label="执行人员", queryType=QueryType.LIKE),
 		@Column(name="finish_user_code", attrName="finishUserCode", label="实际完成人"),
 		@Column(name="device_id", attrName="deviceId", label="设备"),
@@ -61,6 +62,7 @@ public class MesDevicePreventTask extends DataEntity<MesDevicePreventTask> {
 	
 	private static final long serialVersionUID = 1L;
 	private String preventId;		// 任务清单
+	private String batchId;		// 同一份维护计划的批次号,周期任务共用
 	private String userCode;		// 执行人员(多人逗号分隔冗余)
 	private String finishUserCode;		// 实际完成人
 	private String deviceId;		// 设备
@@ -75,6 +77,10 @@ public class MesDevicePreventTask extends DataEntity<MesDevicePreventTask> {
 	private String finishUserName;		// 实际完成人名称
 	/** 周期(天),仅新增排计划时使用,不入库 */
 	private Integer cycleDays;
+	/** 一级列表:该批次任务条数,不入库 */
+	private Long taskCount;
+	/** 一级列表:该批次已完成条数,不入库 */
+	private Long doneCount;
 	@ExcelFields({
 			@ExcelField(title="任务清单", attrName="preventTitle", align= ExcelField.Align.CENTER, sort=20),
 			@ExcelField(title="执行人员", attrName="userName", align= ExcelField.Align.CENTER, sort=30),
@@ -105,6 +111,15 @@ public class MesDevicePreventTask extends DataEntity<MesDevicePreventTask> {
 	public void setPreventId(String preventId) {
 		this.preventId = preventId;
 	}
+
+	@Size(min=0, max=64, message="计划批次长度不能超过 64 个字符")
+	public String getBatchId() {
+		return batchId;
+	}
+
+	public void setBatchId(String batchId) {
+		this.batchId = batchId;
+	}
 	
 	/** 执行人员:表单多选提交为逗号分隔;主表冗余存储,明细以关系表为准 */
 	@Size(min=0, max=2000, message="执行人员长度不能超过 2000 个字符")
@@ -252,6 +267,22 @@ public class MesDevicePreventTask extends DataEntity<MesDevicePreventTask> {
 		this.cycleDays = cycleDays;
 	}
 
+	public Long getTaskCount() {
+		return taskCount;
+	}
+
+	public void setTaskCount(Long taskCount) {
+		this.taskCount = taskCount;
+	}
+
+	public Long getDoneCount() {
+		return doneCount;
+	}
+
+	public void setDoneCount(Long doneCount) {
+		this.doneCount = doneCount;
+	}
+
 	public List<MesDeviceConsumableRecord> getMesDeviceConsumableRecordList() {
 		return mesDeviceConsumableRecordList;
 	}

+ 179 - 0
src/main/java/com/jeesite/modules/mes/entity/MesDeviceVulnerable.java

@@ -0,0 +1,179 @@
+package com.jeesite.modules.mes.entity;
+
+import javax.validation.constraints.Size;
+
+import com.jeesite.common.collect.ListUtils;
+import com.jeesite.common.entity.DataEntity;
+import com.jeesite.common.mybatis.annotation.Column;
+import com.jeesite.common.mybatis.annotation.Table;
+import com.jeesite.common.mybatis.mapper.query.QueryType;
+import com.jeesite.common.utils.excel.annotation.ExcelField;
+import com.jeesite.common.utils.excel.annotation.ExcelField.Align;
+import com.jeesite.common.utils.excel.annotation.ExcelFields;
+
+import java.util.List;
+
+/**
+ * mes_device_vulnerable_listEntity
+ * @author mes
+ * @version 2024-08-05
+ */
+@Table(name="mes_device_vulnerable_list", alias="a", label="mes_device_vulnerable_list信息", columns={
+		@Column(name="id", attrName="id", label="id", isPK=true),
+		@Column(name="oprno", attrName="oprno", label="工位编号"),
+		@Column(name="material_id", attrName="materialId", label="物料编号"),
+		@Column(name="oprno_name", attrName="oprnoName", label="工位名称", queryType=QueryType.LIKE),
+		@Column(name="device_name", attrName="deviceName", label="设备名称", queryType=QueryType.LIKE),
+		@Column(name="model", attrName="model", label="型号"),
+		@Column(name="brand", attrName="brand", label="品牌"),
+		@Column(name="min_inventory", attrName="minInventory", label="最小库存", isUpdateForce=true),
+		@Column(name="max_inventory", attrName="maxInventory", label="最大库存", isUpdateForce=true),
+		@Column(name="unit", attrName="unit", label="单位"),
+		@Column(name="purchase_cycle", attrName="purchaseCycle", label="采购周期"),
+		@Column(name="use_cycle", attrName="useCycle", label="使用周期"),
+		@Column(name="price", attrName="price", label="单价"),
+	}, orderBy="a.id DESC"
+)
+public class MesDeviceVulnerable extends DataEntity<MesDeviceVulnerable> {
+	
+	private static final long serialVersionUID = 1L;
+	private String oprno;		// 工位编号
+	private String materialId;		// 物料编号
+	private String oprnoName;		// 工位名称
+	private String deviceName;		// 设备名称
+	private String model;		// 型号
+	private String brand;		// 品牌
+	private Long minInventory;		// 最小库存
+	private Long maxInventory;		// 最大库存
+	private String unit;		// 单位
+	private String purchaseCycle;		// 采购周期
+	private String useCycle;		// 使用周期
+	private String price;		// 单价
+
+	@ExcelFields({
+		@ExcelField(title="设备名称", attrName="deviceName", align=Align.CENTER, sort=50),
+		@ExcelField(title="型号", attrName="model", align=Align.CENTER, sort=60),
+		@ExcelField(title="品牌", attrName="brand", align=Align.CENTER, sort=70),
+		@ExcelField(title="最小库存", attrName="minInventory", align=Align.CENTER, sort=80),
+		@ExcelField(title="最大库存", attrName="maxInventory", align=Align.CENTER, sort=90),
+		@ExcelField(title="单位", attrName="unit", align=Align.CENTER, sort=100),
+		@ExcelField(title="采购周期", attrName="purchaseCycle", align=Align.CENTER, sort=110),
+		@ExcelField(title="使用周期", attrName="useCycle", align=Align.CENTER, sort=120),
+		@ExcelField(title="单价", attrName="price", align=Align.CENTER, sort=130),
+	})
+	public MesDeviceVulnerable() {
+		this(null);
+	}
+	
+	public MesDeviceVulnerable(String id){
+		super(id);
+	}
+	
+	@Size(min=0, max=20, message="工位编号长度不能超过 20 个字符")
+	public String getOprno() {
+		return oprno;
+	}
+
+	public void setOprno(String oprno) {
+		this.oprno = oprno;
+	}
+	
+	@Size(min=0, max=64, message="物料编号长度不能超过 64 个字符")
+	public String getMaterialId() {
+		return materialId;
+	}
+
+	public void setMaterialId(String materialId) {
+		this.materialId = materialId;
+	}
+	
+	@Size(min=0, max=100, message="工位名称长度不能超过 100 个字符")
+	public String getOprnoName() {
+		return oprnoName;
+	}
+
+	public void setOprnoName(String oprnoName) {
+		this.oprnoName = oprnoName;
+	}
+	
+	@Size(min=0, max=255, message="设备名称长度不能超过 255 个字符")
+	public String getDeviceName() {
+		return deviceName;
+	}
+
+	public void setDeviceName(String deviceName) {
+		this.deviceName = deviceName;
+	}
+	
+	@Size(min=0, max=255, message="型号长度不能超过 255 个字符")
+	public String getModel() {
+		return model;
+	}
+
+	public void setModel(String model) {
+		this.model = model;
+	}
+	
+	@Size(min=0, max=100, message="品牌长度不能超过 100 个字符")
+	public String getBrand() {
+		return brand;
+	}
+
+	public void setBrand(String brand) {
+		this.brand = brand;
+	}
+	
+	public Long getMinInventory() {
+		return minInventory;
+	}
+
+	public void setMinInventory(Long minInventory) {
+		this.minInventory = minInventory;
+	}
+	
+	public Long getMaxInventory() {
+		return maxInventory;
+	}
+
+	public void setMaxInventory(Long maxInventory) {
+		this.maxInventory = maxInventory;
+	}
+	
+	@Size(min=0, max=20, message="单位长度不能超过 20 个字符")
+	public String getUnit() {
+		return unit;
+	}
+
+	public void setUnit(String unit) {
+		this.unit = unit;
+	}
+	
+	@Size(min=0, max=64, message="采购周期长度不能超过 64 个字符")
+	public String getPurchaseCycle() {
+		return purchaseCycle;
+	}
+
+	public void setPurchaseCycle(String purchaseCycle) {
+		this.purchaseCycle = purchaseCycle;
+	}
+	
+	@Size(min=0, max=100, message="使用周期长度不能超过 100 个字符")
+	public String getUseCycle() {
+		return useCycle;
+	}
+
+	public void setUseCycle(String useCycle) {
+		this.useCycle = useCycle;
+	}
+	
+	@Size(min=0, max=64, message="单价长度不能超过 64 个字符")
+	public String getPrice() {
+		return price;
+	}
+
+	public void setPrice(String price) {
+		this.price = price;
+	}
+
+	
+}

+ 88 - 0
src/main/java/com/jeesite/modules/mes/service/MesDeviceFaultCateService.java

@@ -0,0 +1,88 @@
+package com.jeesite.modules.mes.service;
+
+import com.jeesite.common.entity.Page;
+import com.jeesite.common.service.CrudService;
+import com.jeesite.modules.mes.dao.MesDeviceFaultCateDao;
+import com.jeesite.modules.mes.entity.MesDeviceFaultCate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+/**
+ * 设备故障分类Service
+ * @author hzd
+ * @version 2024-07-23
+ */
+@Service
+public class MesDeviceFaultCateService extends CrudService<MesDeviceFaultCateDao, MesDeviceFaultCate> {
+	@Autowired
+	private MesDeviceFaultCateDao mesDeviceFaultCateDao;
+	/**
+	 * 获取单条数据
+	 * @param mesDeviceFaultCate
+	 * @return
+	 */
+	@Override
+	public MesDeviceFaultCate get(MesDeviceFaultCate mesDeviceFaultCate) {
+		return super.get(mesDeviceFaultCate);
+	}
+	
+	/**
+	 * 查询分页数据
+	 * @param mesDeviceFaultCate 查询条件
+	 * @param mesDeviceFaultCate.page 分页对象
+	 * @return
+	 */
+	@Override
+	public Page<MesDeviceFaultCate> findPage(MesDeviceFaultCate mesDeviceFaultCate) {
+		return super.findPage(mesDeviceFaultCate);
+	}
+	
+	/**
+	 * 查询列表数据
+	 * @param mesDeviceFaultCate
+	 * @return
+	 */
+	@Override
+	public List<MesDeviceFaultCate> findList(MesDeviceFaultCate mesDeviceFaultCate) {
+		return super.findList(mesDeviceFaultCate);
+	}
+	
+	/**
+	 * 保存数据(插入或更新)
+	 * @param mesDeviceFaultCate
+	 */
+	@Override
+	@Transactional
+	public void save(MesDeviceFaultCate mesDeviceFaultCate) {
+		super.save(mesDeviceFaultCate);
+	}
+	
+	/**
+	 * 更新状态
+	 * @param mesDeviceFaultCate
+	 */
+	@Override
+	@Transactional
+	public void updateStatus(MesDeviceFaultCate mesDeviceFaultCate) {
+		super.updateStatus(mesDeviceFaultCate);
+	}
+	
+	/**
+	 * 删除数据
+	 * @param mesDeviceFaultCate
+	 */
+	@Override
+	@Transactional
+	public void delete(MesDeviceFaultCate mesDeviceFaultCate) {
+
+		super.delete(mesDeviceFaultCate);
+	}
+	@Transactional
+	public MesDeviceFaultCate findByTitle(String  title) {
+		return mesDeviceFaultCateDao.findByTitle(title);
+	}
+
+}

+ 143 - 0
src/main/java/com/jeesite/modules/mes/service/MesDeviceFaultMaintainService.java

@@ -0,0 +1,143 @@
+package com.jeesite.modules.mes.service;
+
+import com.jeesite.common.config.Global;
+import com.jeesite.common.entity.Page;
+import com.jeesite.common.service.CrudService;
+import com.jeesite.common.service.ServiceException;
+import com.jeesite.common.utils.excel.ExcelImport;
+import com.jeesite.common.validator.ValidatorUtils;
+import com.jeesite.modules.mes.dao.MesDeviceFaultMaintainDao;
+import com.jeesite.modules.mes.entity.MesDeviceFaultMaintain;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.ConstraintViolationException;
+import java.util.List;
+
+/**
+ * 设备故障维护Service
+ * @author mes
+ * @version 2024-07-31
+ */
+@Service
+public class MesDeviceFaultMaintainService extends CrudService<MesDeviceFaultMaintainDao, MesDeviceFaultMaintain> {
+	@Autowired
+	private MesDeviceFaultMaintainDao mesDeviceFaultMaintainDao;
+	/**
+	 * 获取单条数据
+	 * @param mesDeviceFaultMaintain
+	 * @return
+	 */
+	@Override
+	public MesDeviceFaultMaintain get(MesDeviceFaultMaintain mesDeviceFaultMaintain) {
+		return super.get(mesDeviceFaultMaintain);
+	}
+	
+	/**
+	 * 查询分页数据
+	 * @param mesDeviceFaultMaintain 查询条件
+	 * @param mesDeviceFaultMaintain.page 分页对象
+	 * @return
+	 */
+	@Override
+	public Page<MesDeviceFaultMaintain> findPage(MesDeviceFaultMaintain mesDeviceFaultMaintain) {
+		return super.findPage(mesDeviceFaultMaintain);
+	}
+	
+	/**
+	 * 查询列表数据
+	 * @param mesDeviceFaultMaintain
+	 * @return
+	 */
+	@Override
+	public List<MesDeviceFaultMaintain> findList(MesDeviceFaultMaintain mesDeviceFaultMaintain) {
+		return super.findList(mesDeviceFaultMaintain);
+	}
+	
+	/**
+	 * 保存数据(插入或更新)
+	 * @param mesDeviceFaultMaintain
+	 */
+	@Override
+	@Transactional
+	public void save(MesDeviceFaultMaintain mesDeviceFaultMaintain) {
+		super.save(mesDeviceFaultMaintain);
+	}
+
+	/**
+	 * 导入数据
+	 * @param file 导入的数据文件
+	 */
+	@Transactional
+	public String importData(MultipartFile file) {
+		if (file == null){
+			throw new ServiceException(text("请选择导入的数据文件!"));
+		}
+		int successNum = 0; int failureNum = 0;
+		StringBuilder successMsg = new StringBuilder();
+		StringBuilder failureMsg = new StringBuilder();
+		try(ExcelImport ei = new ExcelImport(file, 2, 0)){
+			List<MesDeviceFaultMaintain> list = ei.getDataList(MesDeviceFaultMaintain.class);
+			for (MesDeviceFaultMaintain mesDeviceFaultMaintain : list) {
+				try{
+					ValidatorUtils.validateWithException(mesDeviceFaultMaintain);
+					this.save(mesDeviceFaultMaintain);
+					successNum++;
+					successMsg.append("<br/>" + successNum + "、编号 " + mesDeviceFaultMaintain.getId() + " 导入成功");
+				} catch (Exception e) {
+					failureNum++;
+					String msg = "<br/>" + failureNum + "、编号 " + mesDeviceFaultMaintain.getId() + " 导入失败:";
+					if (e instanceof ConstraintViolationException){
+						ConstraintViolationException cve = (ConstraintViolationException)e;
+						for (ConstraintViolation<?> violation : cve.getConstraintViolations()) {
+							msg += Global.getText(violation.getMessage()) + " ("+violation.getPropertyPath()+")";
+						}
+					}else{
+						msg += e.getMessage();
+					}
+					failureMsg.append(msg);
+					logger.error(msg, e);
+				}
+			}
+		} catch (Exception e) {
+			logger.error(e.getMessage(), e);
+			failureMsg.append(e.getMessage());
+			return failureMsg.toString();
+		}
+		if (failureNum > 0) {
+			failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
+			throw new ServiceException(failureMsg.toString());
+		}else{
+			successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:");
+		}
+		return successMsg.toString();
+	}
+	
+	/**
+	 * 更新状态
+	 * @param mesDeviceFaultMaintain
+	 */
+	@Override
+	@Transactional
+	public void updateStatus(MesDeviceFaultMaintain mesDeviceFaultMaintain) {
+		super.updateStatus(mesDeviceFaultMaintain);
+	}
+	
+	/**
+	 * 删除数据
+	 * @param mesDeviceFaultMaintain
+	 */
+	@Override
+	@Transactional
+	public void delete(MesDeviceFaultMaintain mesDeviceFaultMaintain) {
+		super.delete(mesDeviceFaultMaintain);
+	}
+
+	@Transactional
+	public MesDeviceFaultMaintain findByTitle(String  title) {
+		return mesDeviceFaultMaintainDao.findByTitle(title);
+	}
+}

+ 159 - 0
src/main/java/com/jeesite/modules/mes/service/MesDeviceFaultService.java

@@ -0,0 +1,159 @@
+package com.jeesite.modules.mes.service;
+
+import com.jeesite.common.config.Global;
+import com.jeesite.common.entity.Page;
+import com.jeesite.common.service.CrudService;
+import com.jeesite.common.service.ServiceException;
+import com.jeesite.common.utils.excel.ExcelImport;
+import com.jeesite.common.validator.ValidatorUtils;
+import com.jeesite.modules.file.utils.FileUploadUtils;
+import com.jeesite.modules.mes.dao.MesDeviceFaultDao;
+import com.jeesite.modules.mes.entity.MesDeviceFault;
+import com.jeesite.modules.mes.entity.MesDeviceFaultCate;
+import com.jeesite.modules.mes.entity.MesDeviceFaultMaintain;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.ConstraintViolationException;
+import java.util.List;
+
+/**
+ * 设备故障记录Service
+ * @author hzd
+ * @version 2024-07-23
+ */
+@Service
+public class MesDeviceFaultService extends CrudService<MesDeviceFaultDao, MesDeviceFault> {
+
+	@Autowired
+	private MesDeviceFaultCateService mesDeviceFaultCateService;
+	@Autowired
+	private MesDeviceFaultMaintainService mesDeviceFaultMaintainService;
+	
+	/**
+	 * 获取单条数据
+	 * @param mesDeviceFault
+	 * @return
+	 */
+	@Override
+	public MesDeviceFault get(MesDeviceFault mesDeviceFault) {
+		return super.get(mesDeviceFault);
+	}
+	
+	/**
+	 * 查询分页数据
+	 * @param mesDeviceFault 查询条件
+	 * @param mesDeviceFault.page 分页对象
+	 * @return
+	 */
+	@Override
+	public Page<MesDeviceFault> findPage(MesDeviceFault mesDeviceFault) {
+		return super.findPage(mesDeviceFault);
+	}
+	
+	/**
+	 * 查询列表数据
+	 * @param mesDeviceFault
+	 * @return
+	 */
+	@Override
+	public List<MesDeviceFault> findList(MesDeviceFault mesDeviceFault) {
+		return super.findList(mesDeviceFault);
+	}
+	
+	/**
+	 * 保存数据(插入或更新)
+	 * @param mesDeviceFault
+	 */
+	@Override
+	@Transactional
+	public void save(MesDeviceFault mesDeviceFault) {
+		super.save(mesDeviceFault);
+		// 保存上传图片
+		FileUploadUtils.saveFileUpload(mesDeviceFault, mesDeviceFault.getId(), "mesDeviceFault_image");
+	}
+
+
+	/**
+	 * 导入数据
+	 * @param file 导入的数据文件
+	 */
+	@Transactional
+	public String importData(MultipartFile file) {
+		if (file == null){
+			throw new ServiceException(text("请选择导入的数据文件!"));
+		}
+		int successNum = 0; int failureNum = 0;
+		StringBuilder successMsg = new StringBuilder();
+		StringBuilder failureMsg = new StringBuilder();
+		try(ExcelImport ei = new ExcelImport(file, 2, 0)){
+			List<MesDeviceFault> list = ei.getDataList(MesDeviceFault.class);
+			for (MesDeviceFault mesDeviceFault : list) {
+				try{
+					MesDeviceFaultCate mesDeviceFaultCate = mesDeviceFaultCateService.findByTitle(mesDeviceFault.getCateTitle());
+					if (mesDeviceFaultCate == null){
+						throw  new Exception("故障分类:"+mesDeviceFault.getCateTitle()+"不存在	,请检查后重试!");
+					}
+					mesDeviceFault.setCateId(mesDeviceFaultCate.getId());
+					MesDeviceFaultMaintain mesDeviceFaultMaintain = mesDeviceFaultMaintainService.findByTitle(mesDeviceFault.getMaintainTitle());
+					if (mesDeviceFaultMaintain == null){
+						throw  new Exception("故障工序:"+mesDeviceFault.getMaintainTitle()+"不存在	,请检查后重试!");
+					}
+					mesDeviceFault.setMaintainId(mesDeviceFaultMaintain.getId());
+					ValidatorUtils.validateWithException(mesDeviceFault);
+					this.save(mesDeviceFault);
+					successNum++;
+					successMsg.append("<br/>" + successNum + "、编号 " + mesDeviceFault.getId() + " 导入成功");
+				} catch (Exception e) {
+					failureNum++;
+					String msg = "<br/>" + failureNum + "、编号 " + mesDeviceFault.getId() + " 导入失败:";
+					if (e instanceof ConstraintViolationException){
+						ConstraintViolationException cve = (ConstraintViolationException)e;
+						for (ConstraintViolation<?> violation : cve.getConstraintViolations()) {
+							msg += Global.getText(violation.getMessage()) + " ("+violation.getPropertyPath()+")";
+						}
+					}else{
+						msg += e.getMessage();
+					}
+					failureMsg.append(msg);
+					logger.error(msg, e);
+				}
+			}
+		} catch (Exception e) {
+			logger.error(e.getMessage(), e);
+			failureMsg.append(e.getMessage());
+			return failureMsg.toString();
+		}
+		if (failureNum > 0) {
+			failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
+			throw new ServiceException(failureMsg.toString());
+		}else{
+			successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:");
+		}
+		return successMsg.toString();
+	}
+	
+	/**
+	 * 更新状态
+	 * @param mesDeviceFault
+	 */
+	@Override
+	@Transactional
+	public void updateStatus(MesDeviceFault mesDeviceFault) {
+		super.updateStatus(mesDeviceFault);
+	}
+	
+	/**
+	 * 删除数据
+	 * @param mesDeviceFault
+	 */
+	@Override
+	@Transactional
+	public void delete(MesDeviceFault mesDeviceFault) {
+		super.delete(mesDeviceFault);
+	}
+	
+}

+ 81 - 0
src/main/java/com/jeesite/modules/mes/service/MesDeviceOeeCateService.java

@@ -0,0 +1,81 @@
+package com.jeesite.modules.mes.service;
+
+import com.jeesite.common.entity.Page;
+import com.jeesite.common.service.CrudService;
+import com.jeesite.modules.mes.dao.MesDeviceOeeCateDao;
+import com.jeesite.modules.mes.entity.MesDeviceOeeCate;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+/**
+ * 设备OEE阶段Service
+ * @author hzd
+ * @version 2024-08-23
+ */
+@Service
+public class MesDeviceOeeCateService extends CrudService<MesDeviceOeeCateDao, MesDeviceOeeCate> {
+	
+	/**
+	 * 获取单条数据
+	 * @param mesDeviceOeeCate
+	 * @return
+	 */
+	@Override
+	public MesDeviceOeeCate get(MesDeviceOeeCate mesDeviceOeeCate) {
+		return super.get(mesDeviceOeeCate);
+	}
+	
+	/**
+	 * 查询分页数据
+	 * @param mesDeviceOeeCate 查询条件
+	 * @param mesDeviceOeeCate.page 分页对象
+	 * @return
+	 */
+	@Override
+	public Page<MesDeviceOeeCate> findPage(MesDeviceOeeCate mesDeviceOeeCate) {
+		return super.findPage(mesDeviceOeeCate);
+	}
+	
+	/**
+	 * 查询列表数据
+	 * @param mesDeviceOeeCate
+	 * @return
+	 */
+	@Override
+	public List<MesDeviceOeeCate> findList(MesDeviceOeeCate mesDeviceOeeCate) {
+		return super.findList(mesDeviceOeeCate);
+	}
+	
+	/**
+	 * 保存数据(插入或更新)
+	 * @param mesDeviceOeeCate
+	 */
+	@Override
+	@Transactional
+	public void save(MesDeviceOeeCate mesDeviceOeeCate) {
+		super.save(mesDeviceOeeCate);
+	}
+	
+	/**
+	 * 更新状态
+	 * @param mesDeviceOeeCate
+	 */
+	@Override
+	@Transactional
+	public void updateStatus(MesDeviceOeeCate mesDeviceOeeCate) {
+		super.updateStatus(mesDeviceOeeCate);
+	}
+	
+	/**
+	 * 删除数据
+	 * @param mesDeviceOeeCate
+	 */
+	@Override
+	@Transactional
+	public void delete(MesDeviceOeeCate mesDeviceOeeCate) {
+		super.delete(mesDeviceOeeCate);
+	}
+	
+}

+ 148 - 0
src/main/java/com/jeesite/modules/mes/service/MesDeviceOeeService.java

@@ -0,0 +1,148 @@
+package com.jeesite.modules.mes.service;
+
+import com.jeesite.common.config.Global;
+import com.jeesite.common.entity.Page;
+import com.jeesite.common.service.CrudService;
+import com.jeesite.common.service.ServiceException;
+import com.jeesite.common.utils.excel.ExcelImport;
+import com.jeesite.common.validator.ValidatorUtils;
+import com.jeesite.modules.mes.dao.MesDeviceOeeDao;
+import com.jeesite.modules.mes.entity.MesDeviceOee;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.ConstraintViolationException;
+import java.util.List;
+
+/**
+ * OEEService
+ * @author mes
+ * @version 2024-08-02
+ */
+@Service
+public class MesDeviceOeeService extends CrudService<MesDeviceOeeDao, MesDeviceOee> {
+
+	@Autowired
+	private  MesDeviceOeeDao mesDeviceOeeDao;
+	/**
+	 * 获取单条数据
+	 * @param mesDeviceOee
+	 * @return
+	 */
+	@Override
+	public MesDeviceOee get(MesDeviceOee mesDeviceOee) {
+		return super.get(mesDeviceOee);
+	}
+	
+	/**
+	 * 查询分页数据
+	 * @param mesDeviceOee 查询条件
+	 * @param mesDeviceOee.page 分页对象
+	 * @return
+	 */
+	@Override
+	public Page<MesDeviceOee> findPage(MesDeviceOee mesDeviceOee) {
+		return super.findPage(mesDeviceOee);
+	}
+	
+	/**
+	 * 查询列表数据
+	 * @param mesDeviceOee
+	 * @return
+	 */
+	@Override
+	public List<MesDeviceOee> findList(MesDeviceOee mesDeviceOee) {
+		return super.findList(mesDeviceOee);
+	}
+	
+	/**
+	 * 保存数据(插入或更新)
+	 * @param mesDeviceOee
+	 */
+	@Override
+	@Transactional
+	public void save(MesDeviceOee mesDeviceOee) {
+		super.save(mesDeviceOee);
+	}
+
+	/**
+	 * 导入数据
+	 * @param file 导入的数据文件
+	 */
+	@Transactional
+	public String importData(MultipartFile file) {
+		if (file == null){
+			throw new ServiceException(text("请选择导入的数据文件!"));
+		}
+		int successNum = 0; int failureNum = 0;
+		StringBuilder successMsg = new StringBuilder();
+		StringBuilder failureMsg = new StringBuilder();
+		try(ExcelImport ei = new ExcelImport(file, 2, 0)){
+			List<MesDeviceOee> list = ei.getDataList(MesDeviceOee.class);
+			for (MesDeviceOee mesDeviceOee : list) {
+				try{
+					ValidatorUtils.validateWithException(mesDeviceOee);
+					this.save(mesDeviceOee);
+					successNum++;
+					successMsg.append("<br/>" + successNum + "、编号 " + mesDeviceOee.getId() + " 导入成功");
+				} catch (Exception e) {
+					failureNum++;
+					String msg = "<br/>" + failureNum + "、编号 " + mesDeviceOee.getId() + " 导入失败:";
+					if (e instanceof ConstraintViolationException){
+						ConstraintViolationException cve = (ConstraintViolationException)e;
+						for (ConstraintViolation<?> violation : cve.getConstraintViolations()) {
+							msg += Global.getText(violation.getMessage()) + " ("+violation.getPropertyPath()+")";
+						}
+					}else{
+						msg += e.getMessage();
+					}
+					failureMsg.append(msg);
+					logger.error(msg, e);
+				}
+			}
+		} catch (Exception e) {
+			logger.error(e.getMessage(), e);
+			failureMsg.append(e.getMessage());
+			return failureMsg.toString();
+		}
+		if (failureNum > 0) {
+			failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
+			throw new ServiceException(failureMsg.toString());
+		}else{
+			successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:");
+		}
+		return successMsg.toString();
+	}
+	
+	/**
+	 * 更新状态
+	 * @param mesDeviceOee
+	 */
+	@Override
+	@Transactional
+	public void updateStatus(MesDeviceOee mesDeviceOee) {
+		super.updateStatus(mesDeviceOee);
+	}
+	
+	/**
+	 * 删除数据
+	 * @param mesDeviceOee
+	 */
+	@Override
+	@Transactional
+	public void delete(MesDeviceOee mesDeviceOee) {
+		super.delete(mesDeviceOee);
+	}
+
+	/**
+	 * 根据故障工序名称和日期查询
+	 * @param mesDeviceOee
+	 */
+	@Transactional
+	public MesDeviceOee findByDateAndtitle(MesDeviceOee mesDeviceOee) {
+		return mesDeviceOeeDao.findByDateAndtitle(mesDeviceOee);
+	}
+}

+ 69 - 0
src/main/java/com/jeesite/modules/mes/service/MesDevicePreventTaskService.java

@@ -5,6 +5,7 @@ import java.util.Calendar;
 import java.util.Date;
 import java.util.List;
 
+import cn.hutool.core.util.IdUtil;
 import com.jeesite.common.lang.StringUtils;
 import com.jeesite.common.service.ServiceException;
 import com.jeesite.common.mybatis.mapper.query.QueryType;
@@ -126,6 +127,9 @@ public class MesDevicePreventTaskService extends CrudService<MesDevicePreventTas
 		if (mesDevicePreventTask.getIsNewRecord() && StringUtils.isBlank(mesDevicePreventTask.getState())) {
 			mesDevicePreventTask.setState("0");
 		}
+		if (mesDevicePreventTask.getIsNewRecord() && StringUtils.isBlank(mesDevicePreventTask.getBatchId())) {
+			mesDevicePreventTask.setBatchId(IdUtil.getSnowflakeNextIdStr());
+		}
 		// 主表冗余存逗号分隔,便于表单回显与PDA字段兼容
 		mesDevicePreventTask.setUserCode(StringUtils.join(userCodes, ","));
 		StringBuilder nameBuilder = new StringBuilder();
@@ -180,9 +184,11 @@ public class MesDevicePreventTaskService extends CrudService<MesDevicePreventTas
 
 		Date cursor = firstStart;
 		int count = 0;
+		String batchId = IdUtil.getSnowflakeNextIdStr();
 		while (!cursor.after(rangeEnd)) {
 			MesDevicePreventTask task = new MesDevicePreventTask();
 			task.setIsNewRecord(true);
+			task.setBatchId(batchId);
 			task.setPreventId(template.getPreventId());
 			task.setDeviceId(template.getDeviceId());
 			task.setStartDate(cursor);
@@ -219,6 +225,46 @@ public class MesDevicePreventTaskService extends CrudService<MesDevicePreventTas
 	}
 
 	/**
+	 * 维护计划一级列表:按批次分页,一行代表一份计划。
+	 */
+	public Page<MesDevicePreventTask> findPlanPage(MesDevicePreventTask query) {
+		Page<MesDevicePreventTask> page = query.getPage();
+		query.setPage(null);
+		long count = dao.findPlanCount(query);
+		page.setCount(count);
+		query.setPage(page);
+		List<MesDevicePreventTask> list = dao.findPlanList(query);
+		if (list != null) {
+			for (MesDevicePreventTask item : list) {
+				fillUserNameFromCodes(item);
+			}
+		}
+		page.setList(list);
+		return page;
+	}
+
+	/**
+	 * 删除同一批次下的全部周期任务
+	 */
+	@Transactional
+	public void deleteByBatch(String batchId) {
+		if (StringUtils.isBlank(batchId)) {
+			return;
+		}
+		MesDevicePreventTask query = new MesDevicePreventTask();
+		query.setBatchId(batchId);
+		List<MesDevicePreventTask> list = dao.findList(query);
+		if (list == null) {
+			return;
+		}
+		for (MesDevicePreventTask task : list) {
+			if (task != null && StringUtils.isNotBlank(task.getId())) {
+				this.delete(task);
+			}
+		}
+	}
+
+	/**
 	 * 按执行人过滤计划(我的计划 / PDA ulist)
 	 * 不改接口入参:外部仍可传 userCode,此处改为走关系表
 	 */
@@ -309,6 +355,29 @@ public class MesDevicePreventTaskService extends CrudService<MesDevicePreventTas
 	}
 
 	/**
+	 * 按主表冗余的执行人编码填充名称(一级汇总行没有单条任务主键)
+	 */
+	private void fillUserNameFromCodes(MesDevicePreventTask entity) {
+		if (entity == null || StringUtils.isBlank(entity.getUserCode())) {
+			return;
+		}
+		String[] arr = StringUtils.split(entity.getUserCode(), ",");
+		if (arr == null) {
+			return;
+		}
+		List<String> names = new ArrayList<>();
+		for (String code : arr) {
+			String userCode = StringUtils.trim(code);
+			if (StringUtils.isBlank(userCode)) {
+				continue;
+			}
+			User user = UserUtils.get(userCode);
+			names.add(user != null && StringUtils.isNotBlank(user.getUserName()) ? user.getUserName() : userCode);
+		}
+		entity.setUserName(StringUtils.join(names, ","));
+	}
+
+	/**
 	 * 填充执行人名称(关系表优先,兼容主表冗余)
 	 */
 	private void fillAssigneeDisplay(MesDevicePreventTask entity) {

+ 137 - 0
src/main/java/com/jeesite/modules/mes/service/MesDeviceVulnerableService.java

@@ -0,0 +1,137 @@
+package com.jeesite.modules.mes.service;
+
+import java.util.List;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.jeesite.common.entity.Page;
+import com.jeesite.common.service.CrudService;
+import com.jeesite.modules.mes.entity.MesDeviceVulnerable;
+import com.jeesite.modules.mes.dao.MesDeviceVulnerableDao;
+import com.jeesite.common.service.ServiceException;
+import com.jeesite.common.config.Global;
+import com.jeesite.common.validator.ValidatorUtils;
+import com.jeesite.common.utils.excel.ExcelImport;
+import org.springframework.web.multipart.MultipartFile;
+import javax.validation.ConstraintViolation;
+import javax.validation.ConstraintViolationException;
+
+/**
+ * mes_device_vulnerable_listService
+ * @author mes
+ * @version 2024-08-05
+ */
+@Service
+public class MesDeviceVulnerableService extends CrudService<MesDeviceVulnerableDao, MesDeviceVulnerable> {
+	
+	/**
+	 * 获取单条数据
+	 * @param mesDeviceVulnerable
+	 * @return
+	 */
+	@Override
+	public MesDeviceVulnerable get(MesDeviceVulnerable mesDeviceVulnerable) {
+		return super.get(mesDeviceVulnerable);
+	}
+	
+	/**
+	 * 查询分页数据
+	 * @param mesDeviceVulnerable 查询条件
+	 * @param mesDeviceVulnerable.page 分页对象
+	 * @return
+	 */
+	@Override
+	public Page<MesDeviceVulnerable> findPage(MesDeviceVulnerable mesDeviceVulnerable) {
+		return super.findPage(mesDeviceVulnerable);
+	}
+	
+	/**
+	 * 查询列表数据
+	 * @param mesDeviceVulnerable
+	 * @return
+	 */
+	@Override
+	public List<MesDeviceVulnerable> findList(MesDeviceVulnerable mesDeviceVulnerable) {
+		return super.findList(mesDeviceVulnerable);
+	}
+	
+	/**
+	 * 保存数据(插入或更新)
+	 * @param mesDeviceVulnerable
+	 */
+	@Override
+	@Transactional
+	public void save(MesDeviceVulnerable mesDeviceVulnerable) {
+		super.save(mesDeviceVulnerable);
+	}
+
+	/**
+	 * 导入数据
+	 * @param file 导入的数据文件
+	 */
+	@Transactional
+	public String importData(MultipartFile file) {
+		if (file == null){
+			throw new ServiceException(text("请选择导入的数据文件!"));
+		}
+		int successNum = 0; int failureNum = 0;
+		StringBuilder successMsg = new StringBuilder();
+		StringBuilder failureMsg = new StringBuilder();
+		try(ExcelImport ei = new ExcelImport(file, 2, 0)){
+			List<MesDeviceVulnerable> list = ei.getDataList(MesDeviceVulnerable.class);
+			for (MesDeviceVulnerable mesDeviceVulnerable : list) {
+				try{
+					ValidatorUtils.validateWithException(mesDeviceVulnerable);
+					this.save(mesDeviceVulnerable);
+					successNum++;
+					successMsg.append("<br/>" + successNum + "、编号 " + mesDeviceVulnerable.getId() + " 导入成功");
+				} catch (Exception e) {
+					failureNum++;
+					String msg = "<br/>" + failureNum + "、编号 " + mesDeviceVulnerable.getId() + " 导入失败:";
+					if (e instanceof ConstraintViolationException){
+						ConstraintViolationException cve = (ConstraintViolationException)e;
+						for (ConstraintViolation<?> violation : cve.getConstraintViolations()) {
+							msg += Global.getText(violation.getMessage()) + " ("+violation.getPropertyPath()+")";
+						}
+					}else{
+						msg += e.getMessage();
+					}
+					failureMsg.append(msg);
+					logger.error(msg, e);
+				}
+			}
+		} catch (Exception e) {
+			logger.error(e.getMessage(), e);
+			failureMsg.append(e.getMessage());
+			return failureMsg.toString();
+		}
+		if (failureNum > 0) {
+			failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
+			throw new ServiceException(failureMsg.toString());
+		}else{
+			successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:");
+		}
+		return successMsg.toString();
+	}
+	
+	/**
+	 * 更新状态
+	 * @param mesDeviceVulnerable
+	 */
+	@Override
+	@Transactional
+	public void updateStatus(MesDeviceVulnerable mesDeviceVulnerable) {
+		super.updateStatus(mesDeviceVulnerable);
+	}
+	
+	/**
+	 * 删除数据
+	 * @param mesDeviceVulnerable
+	 */
+	@Override
+	@Transactional
+	public void delete(MesDeviceVulnerable mesDeviceVulnerable) {
+		super.delete(mesDeviceVulnerable);
+	}
+	
+}

+ 47 - 0
src/main/java/com/jeesite/modules/mes/util/CommonUitl.java

@@ -612,6 +612,53 @@ public class CommonUitl {
         return xml;
     }
 
+    /**
+     * 获取两个日期之间的每一天,含起止日。
+     */
+    public static List<String> getDayList(String bigtimeStr, String endTimeStr) {
+        List<String> datas = new LinkedList<>();
+        try {
+            Date bigtime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(bigtimeStr + " 00:00:00");
+            Date endtime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(endTimeStr + " 00:00:00");
+            List<Date> lDate = new ArrayList<>();
+            lDate.add(bigtime);
+            Calendar calBegin = Calendar.getInstance();
+            calBegin.setTime(bigtime);
+            while (endtime.after(calBegin.getTime())) {
+                calBegin.add(Calendar.DAY_OF_MONTH, 1);
+                lDate.add(calBegin.getTime());
+            }
+            for (Date date : lDate) {
+                datas.add(new SimpleDateFormat("yyyy-MM-dd").format(date));
+            }
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return datas;
+    }
+
+    public static Date String2Date2(String dateString) {
+        try {
+            return new SimpleDateFormat("yyyy-MM-dd").parse(dateString);
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    public static List<String> getBeforeDays(Integer maxday) {
+        Calendar calendar = Calendar.getInstance();
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        List<String> list = new ArrayList<>();
+        list.add(sdf.format(new Date()));
+        int days = maxday == null ? 1 : maxday;
+        for (int i = 0; i < (days - 1); i++) {
+            calendar.add(Calendar.DAY_OF_MONTH, -1);
+            list.add(sdf.format(calendar.getTime()));
+        }
+        return list;
+    }
+
     public static MesSearchDateReq getSearchDate(){
         String days = Global.getConfig("mes.search.days");
         if(StringUtils.isEmpty(days)){

+ 119 - 0
src/main/java/com/jeesite/modules/mes/web/MesDeviceFaultCateController.java

@@ -0,0 +1,119 @@
+package com.jeesite.modules.mes.web;
+
+import com.jeesite.common.config.Global;
+import com.jeesite.common.entity.Page;
+import com.jeesite.common.web.BaseController;
+import com.jeesite.modules.mes.entity.MesDeviceFaultCate;
+import com.jeesite.modules.mes.service.MesDeviceFaultCateService;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * 设备故障分类Controller
+ * @author hzd
+ * @version 2024-07-23
+ */
+@Controller
+@RequestMapping(value = "${adminPath}/mes/mesDeviceFaultCate")
+public class MesDeviceFaultCateController extends BaseController {
+
+	@Autowired
+	private MesDeviceFaultCateService mesDeviceFaultCateService;
+	
+	/**
+	 * 获取数据
+	 */
+	@ModelAttribute
+	public MesDeviceFaultCate get(String id, boolean isNewRecord) {
+		return mesDeviceFaultCateService.get(id, isNewRecord);
+	}
+	
+	/**
+	 * 查询列表
+	 */
+	@RequiresPermissions("mes:mesDeviceFaultCate:view")
+	@RequestMapping(value = {"list", ""})
+	public String list(MesDeviceFaultCate mesDeviceFaultCate, Model model) {
+		model.addAttribute("mesDeviceFaultCate", mesDeviceFaultCate);
+		return "modules/mes/mesDeviceFaultCateList";
+	}
+	
+	/**
+	 * 查询列表数据
+	 */
+	@RequiresPermissions("mes:mesDeviceFaultCate:view")
+	@RequestMapping(value = "listData")
+	@ResponseBody
+	public Page<MesDeviceFaultCate> listData(MesDeviceFaultCate mesDeviceFaultCate, HttpServletRequest request, HttpServletResponse response) {
+		mesDeviceFaultCate.setPage(new Page<>(request, response));
+		Page<MesDeviceFaultCate> page = mesDeviceFaultCateService.findPage(mesDeviceFaultCate);
+		return page;
+	}
+
+	/**
+	 * 查看编辑表单
+	 */
+	@RequiresPermissions("mes:mesDeviceFaultCate:view")
+	@RequestMapping(value = "form")
+	public String form(MesDeviceFaultCate mesDeviceFaultCate, Model model) {
+		model.addAttribute("mesDeviceFaultCate", mesDeviceFaultCate);
+		return "modules/mes/mesDeviceFaultCateForm";
+	}
+
+	/**
+	 * 保存数据
+	 */
+	@RequiresPermissions("mes:mesDeviceFaultCate:edit")
+	@PostMapping(value = "save")
+	@ResponseBody
+	public String save(@Validated MesDeviceFaultCate mesDeviceFaultCate) {
+		mesDeviceFaultCateService.save(mesDeviceFaultCate);
+		return renderResult(Global.TRUE, text("保存设备故障分类成功!"));
+	}
+	
+	/**
+	 * 停用数据
+	 */
+	@RequiresPermissions("mes:mesDeviceFaultCate:edit")
+	@RequestMapping(value = "disable")
+	@ResponseBody
+	public String disable(MesDeviceFaultCate mesDeviceFaultCate) {
+		mesDeviceFaultCate.setStatus(MesDeviceFaultCate.STATUS_DISABLE);
+		mesDeviceFaultCateService.updateStatus(mesDeviceFaultCate);
+		return renderResult(Global.TRUE, text("停用设备故障分类成功"));
+	}
+	
+	/**
+	 * 启用数据
+	 */
+	@RequiresPermissions("mes:mesDeviceFaultCate:edit")
+	@RequestMapping(value = "enable")
+	@ResponseBody
+	public String enable(MesDeviceFaultCate mesDeviceFaultCate) {
+		mesDeviceFaultCate.setStatus(MesDeviceFaultCate.STATUS_NORMAL);
+		mesDeviceFaultCateService.updateStatus(mesDeviceFaultCate);
+		return renderResult(Global.TRUE, text("启用设备故障分类成功"));
+	}
+	
+	/**
+	 * 删除数据
+	 */
+	@RequiresPermissions("mes:mesDeviceFaultCate:edit")
+	@RequestMapping(value = "delete")
+	@ResponseBody
+	public String delete(MesDeviceFaultCate mesDeviceFaultCate) {
+		mesDeviceFaultCateService.delete(mesDeviceFaultCate);
+		return renderResult(Global.TRUE, text("删除设备故障分类成功!"));
+	}
+	
+}

+ 452 - 0
src/main/java/com/jeesite/modules/mes/web/MesDeviceFaultController.java

@@ -0,0 +1,452 @@
+package com.jeesite.modules.mes.web;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.jeesite.common.collect.ListUtils;
+import com.jeesite.common.collect.MapUtils;
+import com.jeesite.common.config.Global;
+import com.jeesite.common.entity.Page;
+import com.jeesite.common.lang.DateUtils;
+import com.jeesite.common.mybatis.mapper.query.QueryType;
+import com.jeesite.common.utils.excel.ExcelExport;
+import com.jeesite.common.utils.excel.annotation.ExcelField.Type;
+import com.jeesite.common.web.BaseController;
+import com.jeesite.modules.mes.entity.MesDeviceFault;
+import com.jeesite.modules.mes.entity.MesDeviceFaultCate;
+import com.jeesite.modules.mes.entity.MesDeviceFaultMaintain;
+import com.jeesite.modules.mes.entity.MesDeviceOee;
+import com.jeesite.modules.mes.resp.CommonResp;
+import com.jeesite.modules.mes.service.MesDeviceFaultCateService;
+import com.jeesite.modules.mes.service.MesDeviceFaultMaintainService;
+import com.jeesite.modules.mes.service.MesDeviceFaultService;
+import com.jeesite.modules.mes.service.MesDeviceOeeService;
+import com.jeesite.modules.mes.util.CommonUitl;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.*;
+
+/**
+ * 设备故障记录Controller
+ * @author hzd
+ * @version 2024-07-23
+ */
+@Controller
+@RequestMapping(value = "${adminPath}/mes/mesDeviceFault")
+public class MesDeviceFaultController extends BaseController {
+
+	@Autowired
+	private MesDeviceFaultService mesDeviceFaultService;
+
+	@Autowired
+	private MesDeviceFaultCateService mesDeviceFaultCateService;
+	@Autowired
+	private MesDeviceFaultMaintainService mesDeviceFaultMaintainService;
+	@Autowired
+	private MesDeviceOeeService mesDeviceOeeService;
+	
+	/**
+	 * 获取数据
+	 */
+	@ModelAttribute
+	public MesDeviceFault get(String id, boolean isNewRecord) {
+		return mesDeviceFaultService.get(id, isNewRecord);
+	}
+	
+	/**
+	 * 查询列表
+	 */
+	@RequiresPermissions("mes:mesDeviceFault:view")
+	@RequestMapping(value = {"list", ""})
+	public String list(MesDeviceFault mesDeviceFault, Model model) {
+		model.addAttribute("mesDeviceFault", mesDeviceFault);
+		MesDeviceFaultCate mesDeviceFaultCate = new MesDeviceFaultCate();
+		mesDeviceFaultCate.setStatus("0");
+		model.addAttribute("mesDeviceFaultCate", mesDeviceFaultCateService.findList(mesDeviceFaultCate));
+		MesDeviceFaultMaintain mesDeviceFaultMaintain = new MesDeviceFaultMaintain();
+		mesDeviceFaultMaintain.setStatus("0");
+		model.addAttribute("mesDeviceFaultMaintain", mesDeviceFaultMaintainService.findList(mesDeviceFaultMaintain));
+		return "modules/mes/mesDeviceFaultList";
+	}
+	
+	/**
+	 * 查询列表数据
+	 */
+	@RequiresPermissions("mes:mesDeviceFault:view")
+	@RequestMapping(value = "listData")
+	@ResponseBody
+	public Page<MesDeviceFault> listData(MesDeviceFault mesDeviceFault, HttpServletRequest request, HttpServletResponse response) {
+		mesDeviceFault.setPage(new Page<>(request, response));
+		Page<MesDeviceFault> page = mesDeviceFaultService.findPage(mesDeviceFault);
+		return page;
+	}
+
+	/**
+	 * 查看编辑表单
+	 */
+	@RequiresPermissions("mes:mesDeviceFault:view")
+	@RequestMapping(value = "form")
+	public String form(MesDeviceFault mesDeviceFault, Model model) {
+		model.addAttribute("mesDeviceFault", mesDeviceFault);
+		MesDeviceFaultCate mesDeviceFaultCate = new MesDeviceFaultCate();
+		mesDeviceFaultCate.setStatus("0");
+		model.addAttribute("mesDeviceFaultCate", mesDeviceFaultCateService.findList(mesDeviceFaultCate));
+		MesDeviceFaultMaintain mesDeviceFaultMaintain = new MesDeviceFaultMaintain();
+		mesDeviceFaultMaintain.setStatus("0");
+		model.addAttribute("mesDeviceFaultMaintain", mesDeviceFaultMaintainService.findList(mesDeviceFaultMaintain));
+
+		return "modules/mes/mesDeviceFaultForm";
+	}
+
+	@RequiresPermissions("mes:mesDeviceFault:view")
+	@RequestMapping(value = "tj")
+	public String tj(MesDeviceFault mesDeviceFault, Model model) {
+		model.addAttribute("mesDeviceFault", mesDeviceFault);
+		MesDeviceFaultCate mesDeviceFaultCate = new MesDeviceFaultCate();
+		mesDeviceFaultCate.setStatus("0");
+		model.addAttribute("mesDeviceFaultCate", mesDeviceFaultCateService.findList(mesDeviceFaultCate));
+		MesDeviceFaultMaintain mesDeviceFaultMaintain = new MesDeviceFaultMaintain();
+		mesDeviceFaultMaintain.setStatus("0");
+		model.addAttribute("mesDeviceFaultMaintain", mesDeviceFaultMaintainService.findList(mesDeviceFaultMaintain));
+		MesDeviceOee mesDeviceOee = new MesDeviceOee();
+		mesDeviceOee.setStatus("0");
+		model.addAttribute("mesDeviceOee", mesDeviceOeeService.findList(mesDeviceOee));
+		return "modules/mes/mesDeviceFaultTj";
+	}
+
+	@RequiresPermissions("mes:mesDeviceFault:view")
+	@RequestMapping(value = "tj2")
+	public String tj2(MesDeviceFault mesDeviceFault, Model model) {
+		model.addAttribute("mesDeviceFault", mesDeviceFault);
+		MesDeviceFaultCate mesDeviceFaultCate = new MesDeviceFaultCate();
+		mesDeviceFaultCate.setStatus("0");
+		model.addAttribute("mesDeviceFaultCate", mesDeviceFaultCateService.findList(mesDeviceFaultCate));
+		MesDeviceFaultMaintain mesDeviceFaultMaintain = new MesDeviceFaultMaintain();
+		mesDeviceFaultMaintain.setStatus("0");
+		model.addAttribute("mesDeviceFaultMaintain", mesDeviceFaultMaintainService.findList(mesDeviceFaultMaintain));
+		return "modules/mes/mesDeviceFaultTj2";
+	}
+
+	@RequestMapping(value = "tjData1")
+	@ResponseBody
+	public CommonResp tjData1(MesDeviceFault mesDeviceFault) {
+		CommonResp<Map<String, Object>> resp = new CommonResp<>();
+		Map<String, Object> map = MapUtils.newHashMap();
+		mesDeviceFault.setStatus("0");
+
+		MesDeviceFaultCate mesDeviceFaultCate2 = new MesDeviceFaultCate();
+		mesDeviceFaultCate2.setStatus("0");
+		List<MesDeviceFaultCate> cates = mesDeviceFaultCateService.findList(mesDeviceFaultCate2);
+
+		List<Map> lists = new ArrayList<>();
+		for (MesDeviceFaultCate mesDeviceFaultCate:cates){
+			Map<String, Object> map2 = MapUtils.newHashMap();
+			map2.put("name",mesDeviceFaultCate.getTitle());
+
+			mesDeviceFault.setCateId(mesDeviceFaultCate.getId());
+			Long jpp1 = mesDeviceFaultService.findCount(mesDeviceFault);
+			map2.put("value",jpp1);
+			lists.add(map2);
+		}
+
+		map.put("lists",lists);
+
+		resp.setData(map);
+		resp.setResult(Global.TRUE);
+		return resp;
+	}
+
+	@RequestMapping(value = "tjData2")
+	@ResponseBody
+	public CommonResp tjData2(MesDeviceFault mesDeviceFault) {
+		CommonResp<Map<String, Object>> resp = new CommonResp<>();
+		Map<String, Object> map = MapUtils.newHashMap();
+		mesDeviceFault.setStatus("0");
+
+		MesDeviceFaultCate mesDeviceFaultCate2 = new MesDeviceFaultCate();
+		mesDeviceFaultCate2.setStatus("0");
+		List<MesDeviceFaultCate> cates = mesDeviceFaultCateService.findList(mesDeviceFaultCate2);
+
+		List<Map<String, String>> list1 = new ArrayList<>();
+		Map<String, String> map21 = MapUtils.newHashMap();
+		map21.put("id","1");
+		map21.put("title","A");
+		list1.add(map21);
+		Map<String, String> map211 = MapUtils.newHashMap();
+		map211.put("id","2");
+		map211.put("title","B");
+		list1.add(map211);
+		Map<String, String> map22 = MapUtils.newHashMap();
+		map22.put("id","3");
+		map22.put("title","C");
+		list1.add(map22);
+		Map<String, String> map23 = MapUtils.newHashMap();
+		map23.put("id","4");
+		map23.put("title","D");
+		list1.add(map23);
+
+
+		List<Map> lists = new ArrayList<>();
+		for (Map<String, String> map3:list1){
+			Map<String, Object> map4 = MapUtils.newHashMap();
+			map4.put("name",map3.get("title"));
+
+			mesDeviceFault.setLevel(map3.get("id"));
+			Long jpp1 = mesDeviceFaultService.findCount(mesDeviceFault);
+			map4.put("value",jpp1);
+			lists.add(map4);
+		}
+
+		map.put("lists",lists);
+
+		resp.setData(map);
+		resp.setResult(Global.TRUE);
+		return resp;
+	}
+
+	@RequestMapping(value = "tjData3")
+	@ResponseBody
+	public CommonResp tjData3(MesDeviceFault mesDeviceFault) {
+		CommonResp<Map<String, Object>> resp = new CommonResp<>();
+		Map<String, Object> map = MapUtils.newHashMap();
+
+		mesDeviceFault.setStatus("0");
+
+		List<String> days = CommonUitl.getBeforeDays(30);
+		Collections.sort(days);
+
+		List<Long> pNums = new ArrayList<>();
+		for(String day:days){
+			String csdate = day + " 00:00:00";
+			String cedate = day + " 23:59:59";
+			mesDeviceFault.setStartDate_gte(CommonUitl.String2Date(csdate));
+			mesDeviceFault.setStartDate_lte(CommonUitl.String2Date(cedate));
+			Long jpp1 = mesDeviceFaultService.findCount(mesDeviceFault);
+			pNums.add(jpp1);
+		}
+
+		map.put("days",days);
+		map.put("lists",pNums);
+
+		resp.setData(map);
+		resp.setResult(Global.TRUE);
+		return resp;
+	}
+
+	@RequestMapping(value = "tjData4")
+	@ResponseBody
+	public CommonResp tjData4(MesDeviceFault mesDeviceFault) {
+		CommonResp<Map<String, Object>> resp = new CommonResp<>();
+		Map<String, Object> map = MapUtils.newHashMap();
+
+		mesDeviceFault.setStatus("0");
+
+		List<String> days = CommonUitl.getBeforeDays(30);
+		Collections.sort(days);
+
+		List<Integer> pNums = new ArrayList<>();
+		for(String day:days){
+			String csdate = day + " 00:00:00";
+			String cedate = day + " 23:59:59";
+			mesDeviceFault.setStartDate_gte(CommonUitl.String2Date(csdate));
+			mesDeviceFault.setStartDate_lte(CommonUitl.String2Date(cedate));
+			List<MesDeviceFault> mdfs = mesDeviceFaultService.findList(mesDeviceFault);
+			Integer mins = 0;
+			for (MesDeviceFault mesDeviceFault1:mdfs){
+				mins += mesDeviceFault1.getDuration();
+			}
+			pNums.add(mins);
+		}
+
+		map.put("days",days);
+		map.put("lists",pNums);
+
+		resp.setData(map);
+		resp.setResult(Global.TRUE);
+		return resp;
+	}
+
+
+	//mtbf mttr
+	@RequestMapping(value = "tjData6")
+	@ResponseBody
+	public CommonResp tjData6(MesDeviceFault mesDeviceFault) {
+		CommonResp<HashMap<String, List<Object>>> resp = new CommonResp<>();
+		Date startDate = mesDeviceFault.getStartDate();
+		Date endDate = mesDeviceFault.getEndDate();
+
+		if (startDate == null && endDate == null) {
+			LocalDateTime now = LocalDateTime.now().withMinute(0).withSecond(0).withNano(0);
+			endDate = Date.from(now.atZone(ZoneId.systemDefault()).toInstant());
+			startDate = Date.from(now.minusDays(7).atZone(ZoneId.systemDefault()).toInstant());
+		} else if (startDate == null || endDate == null) {
+			resp.setResult(Global.FALSE);
+			resp.setMessage("开始时间和结束时间必须同时填写!");
+			return resp;
+		}
+
+		MesDeviceFaultMaintain mesDeviceFaultMaintain = new MesDeviceFaultMaintain();
+		mesDeviceFaultMaintain.setId(mesDeviceFault.getMaintainId());
+		List<MesDeviceFaultMaintain> list = mesDeviceFaultMaintainService.findList(mesDeviceFaultMaintain);
+
+		// Initialize JSON objects
+		ObjectMapper mapper = new ObjectMapper();
+		ObjectNode chartData = mapper.createObjectNode();
+		ArrayNode xAxisData = mapper.createArrayNode();
+		ArrayNode legendData = mapper.createArrayNode();
+		ArrayNode seriesData = mapper.createArrayNode();
+
+		legendData.add("mttr");
+		legendData.add("mtbf");
+
+		List<Double> mttrList = new ArrayList<>();
+		List<Double> mtbfList = new ArrayList<>();
+
+		for (MesDeviceFaultMaintain deviceFaultMaintain : list) {
+			String id = deviceFaultMaintain.getId();
+			MesDeviceFault mesDeviceFault1 = new MesDeviceFault();
+			mesDeviceFault1.setMaintainId(id);
+			mesDeviceFault1.getSqlMap().getWhere().and("a.start_date", QueryType.GTE, startDate);
+			mesDeviceFault1.getSqlMap().getWhere().and("a.end_date", QueryType.LTE, endDate);
+			List<MesDeviceFault> mesDeviceFaults = mesDeviceFaultService.findList(mesDeviceFault1);
+
+			// Calculate MTTR
+			int hour = 0;
+			for (MesDeviceFault deviceFault : mesDeviceFaults) {
+				Integer duration = deviceFault.getDuration();
+				hour += duration / 60;
+			}
+			double mttr = (double) hour / mesDeviceFaults.size();
+			mttrList.add(mttr);
+
+			// Calculate MTBF
+			Instant startInstant = startDate.toInstant();
+			Instant endInstant = endDate.toInstant();
+			double hours = Duration.between(startInstant, endInstant).toMillis() / (1000.0 * 60 * 60);
+			double hourAll = hours * mesDeviceFaults.size();
+			double mtbf = hourAll / mesDeviceFaults.size();
+			mtbfList.add(mtbf);
+
+			xAxisData.add(deviceFaultMaintain.getTitle());
+		}
+
+		// Create series data
+		ObjectNode mttrSeries = mapper.createObjectNode();
+		mttrSeries.put("name", "mttr");
+		mttrSeries.set("data", mapper.valueToTree(mttrList));
+		seriesData.add(mttrSeries);
+
+		ObjectNode mtbfSeries = mapper.createObjectNode();
+		mtbfSeries.put("name", "mtbf");
+		mtbfSeries.set("data", mapper.valueToTree(mtbfList));
+		seriesData.add(mtbfSeries);
+
+		// Add all data to the root JSON object
+		chartData.put("title", "Fault Analysis");
+		chartData.set("xAxisData", xAxisData);
+		chartData.set("legendData", legendData);
+		chartData.set("seriesData", seriesData);
+
+		HashMap<String, List<Object>> dataMap = new HashMap<>();
+		dataMap.put("xAxisData", mapper.convertValue(xAxisData, List.class));
+		dataMap.put("legendData", mapper.convertValue(legendData, List.class));
+		dataMap.put("seriesData", mapper.convertValue(seriesData, List.class));
+
+		System.out.println(dataMap.toString());
+		resp.setData(dataMap);
+		resp.setResult(Global.TRUE);
+		return resp;
+	}
+	/**
+	 * 保存数据
+	 */
+	@RequiresPermissions("mes:mesDeviceFault:edit")
+	@PostMapping(value = "save")
+	@ResponseBody
+	public String save(@Validated MesDeviceFault mesDeviceFault) {
+
+		if(mesDeviceFault.getStartDate() != null && mesDeviceFault.getEndDate() != null){
+			if(mesDeviceFault.getStartDate().getTime() >= mesDeviceFault.getEndDate().getTime()){
+				return renderResult(Global.FALSE, text("结束时间必须大于开始时间!"));
+			}
+
+			Integer interval = Math.round((mesDeviceFault.getEndDate().getTime() - mesDeviceFault.getStartDate().getTime())/60000);
+			logger.info("duration:"+interval);
+			mesDeviceFault.setDuration(interval);
+		}else{
+			mesDeviceFault.setDuration(0);
+		}
+
+		mesDeviceFaultService.save(mesDeviceFault);
+		return renderResult(Global.TRUE, text("保存设备故障记录成功!"));
+	}
+
+	/**
+	 * 导出数据
+	 */
+	@RequiresPermissions("mes:mesDeviceFault:view")
+	@RequestMapping(value = "exportData")
+	public void exportData(MesDeviceFault mesDeviceFault, HttpServletResponse response) {
+		List<MesDeviceFault> list = mesDeviceFaultService.findList(mesDeviceFault);
+		String fileName = "设备故障记录" + DateUtils.getDate("yyyyMMddHHmmss") + ".xlsx";
+		try(ExcelExport ee = new ExcelExport("设备故障记录", MesDeviceFault.class)){
+			ee.setDataList(list).write(response, fileName);
+		}
+	}
+
+	/**
+	 * 下载模板
+	 */
+	@RequiresPermissions("mes:mesDeviceFault:view")
+	@RequestMapping(value = "importTemplate")
+	public void importTemplate(HttpServletResponse response) {
+		MesDeviceFault mesDeviceFault = new MesDeviceFault();
+		List<MesDeviceFault> list = ListUtils.newArrayList(mesDeviceFault);
+		String fileName = "设备故障记录模板.xlsx";
+		try(ExcelExport ee = new ExcelExport("设备故障记录", MesDeviceFault.class, Type.IMPORT)){
+			ee.setDataList(list).write(response, fileName);
+		}
+	}
+
+	/**
+	 * 导入数据
+	 */
+	@ResponseBody
+	@RequiresPermissions("mes:mesDeviceFault:edit")
+	@PostMapping(value = "importData")
+	public String importData(MultipartFile file) {
+		try {
+			String message = mesDeviceFaultService.importData(file);
+			return renderResult(Global.TRUE, "posfull:"+message);
+		} catch (Exception ex) {
+			return renderResult(Global.FALSE, "posfull:"+ex.getMessage());
+		}
+	}
+	
+	/**
+	 * 删除数据
+	 */
+	@RequiresPermissions("mes:mesDeviceFault:edit")
+	@RequestMapping(value = "delete")
+	@ResponseBody
+	public String delete(MesDeviceFault mesDeviceFault) {
+		mesDeviceFaultService.delete(mesDeviceFault);
+		return renderResult(Global.TRUE, text("删除设备故障记录成功!"));
+	}
+	
+}

+ 167 - 0
src/main/java/com/jeesite/modules/mes/web/MesDeviceFaultMaintainController.java

@@ -0,0 +1,167 @@
+package com.jeesite.modules.mes.web;
+
+import com.jeesite.common.collect.ListUtils;
+import com.jeesite.common.config.Global;
+import com.jeesite.common.entity.Page;
+import com.jeesite.common.lang.DateUtils;
+import com.jeesite.common.utils.excel.ExcelExport;
+import com.jeesite.common.utils.excel.annotation.ExcelField.Type;
+import com.jeesite.common.web.BaseController;
+import com.jeesite.modules.mes.entity.MesDeviceFaultMaintain;
+import com.jeesite.modules.mes.service.MesDeviceFaultMaintainService;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * 设备故障维护Controller
+ * @author mes
+ * @version 2024-07-31
+ */
+@Controller
+@RequestMapping(value = "${adminPath}/mes/mesDeviceFaultMaintain")
+public class MesDeviceFaultMaintainController extends BaseController {
+
+	@Autowired
+	private MesDeviceFaultMaintainService mesDeviceFaultMaintainService;
+	
+	/**
+	 * 获取数据
+	 */
+	@ModelAttribute
+	public MesDeviceFaultMaintain get(String id, boolean isNewRecord) {
+		return mesDeviceFaultMaintainService.get(id, isNewRecord);
+	}
+	
+	/**
+	 * 查询列表
+	 */
+	@RequiresPermissions("mes:mesDeviceFaultMaintain:view")
+	@RequestMapping(value = {"list", ""})
+	public String list(MesDeviceFaultMaintain mesDeviceFaultMaintain, Model model) {
+		model.addAttribute("mesDeviceFaultMaintain", mesDeviceFaultMaintain);
+		return "modules/mes/mesDeviceFaultMaintainList";
+	}
+	
+	/**
+	 * 查询列表数据
+	 */
+	@RequiresPermissions("mes:mesDeviceFaultMaintain:view")
+	@RequestMapping(value = "listData")
+	@ResponseBody
+	public Page<MesDeviceFaultMaintain> listData(MesDeviceFaultMaintain mesDeviceFaultMaintain, HttpServletRequest request, HttpServletResponse response) {
+		mesDeviceFaultMaintain.setPage(new Page<>(request, response));
+		Page<MesDeviceFaultMaintain> page = mesDeviceFaultMaintainService.findPage(mesDeviceFaultMaintain);
+		return page;
+	}
+
+	/**
+	 * 查看编辑表单
+	 */
+	@RequiresPermissions("mes:mesDeviceFaultMaintain:view")
+	@RequestMapping(value = "form")
+	public String form(MesDeviceFaultMaintain mesDeviceFaultMaintain, Model model) {
+		model.addAttribute("mesDeviceFaultMaintain", mesDeviceFaultMaintain);
+		return "modules/mes/mesDeviceFaultMaintainForm";
+	}
+
+	/**
+	 * 保存数据
+	 */
+	@RequiresPermissions("mes:mesDeviceFaultMaintain:edit")
+	@PostMapping(value = "save")
+	@ResponseBody
+	public String save(@Validated MesDeviceFaultMaintain mesDeviceFaultMaintain) {
+		mesDeviceFaultMaintainService.save(mesDeviceFaultMaintain);
+		return renderResult(Global.TRUE, text("保存设备故障维护成功!"));
+	}
+
+	/**
+	 * 导出数据
+	 */
+	@RequiresPermissions("mes:mesDeviceFaultMaintain:view")
+	@RequestMapping(value = "exportData")
+	public void exportData(MesDeviceFaultMaintain mesDeviceFaultMaintain, HttpServletResponse response) {
+		List<MesDeviceFaultMaintain> list = mesDeviceFaultMaintainService.findList(mesDeviceFaultMaintain);
+		String fileName = "设备故障维护" + DateUtils.getDate("yyyyMMddHHmmss") + ".xlsx";
+		try(ExcelExport ee = new ExcelExport("设备故障维护", MesDeviceFaultMaintain.class)){
+			ee.setDataList(list).write(response, fileName);
+		}
+	}
+
+	/**
+	 * 下载模板
+	 */
+	@RequiresPermissions("mes:mesDeviceFaultMaintain:view")
+	@RequestMapping(value = "importTemplate")
+	public void importTemplate(HttpServletResponse response) {
+		MesDeviceFaultMaintain mesDeviceFaultMaintain = new MesDeviceFaultMaintain();
+		List<MesDeviceFaultMaintain> list = ListUtils.newArrayList(mesDeviceFaultMaintain);
+		String fileName = "设备故障维护模板.xlsx";
+		try(ExcelExport ee = new ExcelExport("设备故障维护", MesDeviceFaultMaintain.class, Type.IMPORT)){
+			ee.setDataList(list).write(response, fileName);
+		}
+	}
+
+	/**
+	 * 导入数据
+	 */
+	@ResponseBody
+	@RequiresPermissions("mes:mesDeviceFaultMaintain:edit")
+	@PostMapping(value = "importData")
+	public String importData(MultipartFile file) {
+		try {
+			String message = mesDeviceFaultMaintainService.importData(file);
+			return renderResult(Global.TRUE, "posfull:"+message);
+		} catch (Exception ex) {
+			return renderResult(Global.FALSE, "posfull:"+ex.getMessage());
+		}
+	}
+	
+	/**
+	 * 停用数据
+	 */
+	@RequiresPermissions("mes:mesDeviceFaultMaintain:edit")
+	@RequestMapping(value = "disable")
+	@ResponseBody
+	public String disable(MesDeviceFaultMaintain mesDeviceFaultMaintain) {
+		mesDeviceFaultMaintain.setStatus(MesDeviceFaultMaintain.STATUS_DISABLE);
+		mesDeviceFaultMaintainService.updateStatus(mesDeviceFaultMaintain);
+		return renderResult(Global.TRUE, text("停用设备故障维护成功"));
+	}
+	
+	/**
+	 * 启用数据
+	 */
+	@RequiresPermissions("mes:mesDeviceFaultMaintain:edit")
+	@RequestMapping(value = "enable")
+	@ResponseBody
+	public String enable(MesDeviceFaultMaintain mesDeviceFaultMaintain) {
+		mesDeviceFaultMaintain.setStatus(MesDeviceFaultMaintain.STATUS_NORMAL);
+		mesDeviceFaultMaintainService.updateStatus(mesDeviceFaultMaintain);
+		return renderResult(Global.TRUE, text("启用设备故障维护成功"));
+	}
+	
+	/**
+	 * 删除数据
+	 */
+	@RequiresPermissions("mes:mesDeviceFaultMaintain:edit")
+	@RequestMapping(value = "delete")
+	@ResponseBody
+	public String delete(MesDeviceFaultMaintain mesDeviceFaultMaintain) {
+		mesDeviceFaultMaintainService.delete(mesDeviceFaultMaintain);
+		return renderResult(Global.TRUE, text("删除设备故障维护成功!"));
+	}
+	
+}

+ 119 - 0
src/main/java/com/jeesite/modules/mes/web/MesDeviceOeeCateController.java

@@ -0,0 +1,119 @@
+package com.jeesite.modules.mes.web;
+
+import com.jeesite.common.config.Global;
+import com.jeesite.common.entity.Page;
+import com.jeesite.common.web.BaseController;
+import com.jeesite.modules.mes.entity.MesDeviceOeeCate;
+import com.jeesite.modules.mes.service.MesDeviceOeeCateService;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * 设备OEE阶段Controller
+ * @author hzd
+ * @version 2024-08-23
+ */
+@Controller
+@RequestMapping(value = "${adminPath}/mes/mesDeviceOeeCate")
+public class MesDeviceOeeCateController extends BaseController {
+
+	@Autowired
+	private MesDeviceOeeCateService mesDeviceOeeCateService;
+	
+	/**
+	 * 获取数据
+	 */
+	@ModelAttribute
+	public MesDeviceOeeCate get(String id, boolean isNewRecord) {
+		return mesDeviceOeeCateService.get(id, isNewRecord);
+	}
+	
+	/**
+	 * 查询列表
+	 */
+	@RequiresPermissions("mes:mesDeviceOeeCate:view")
+	@RequestMapping(value = {"list", ""})
+	public String list(MesDeviceOeeCate mesDeviceOeeCate, Model model) {
+		model.addAttribute("mesDeviceOeeCate", mesDeviceOeeCate);
+		return "modules/mes/mesDeviceOeeCateList";
+	}
+	
+	/**
+	 * 查询列表数据
+	 */
+	@RequiresPermissions("mes:mesDeviceOeeCate:view")
+	@RequestMapping(value = "listData")
+	@ResponseBody
+	public Page<MesDeviceOeeCate> listData(MesDeviceOeeCate mesDeviceOeeCate, HttpServletRequest request, HttpServletResponse response) {
+		mesDeviceOeeCate.setPage(new Page<>(request, response));
+		Page<MesDeviceOeeCate> page = mesDeviceOeeCateService.findPage(mesDeviceOeeCate);
+		return page;
+	}
+
+	/**
+	 * 查看编辑表单
+	 */
+	@RequiresPermissions("mes:mesDeviceOeeCate:view")
+	@RequestMapping(value = "form")
+	public String form(MesDeviceOeeCate mesDeviceOeeCate, Model model) {
+		model.addAttribute("mesDeviceOeeCate", mesDeviceOeeCate);
+		return "modules/mes/mesDeviceOeeCateForm";
+	}
+
+	/**
+	 * 保存数据
+	 */
+	@RequiresPermissions("mes:mesDeviceOeeCate:edit")
+	@PostMapping(value = "save")
+	@ResponseBody
+	public String save(@Validated MesDeviceOeeCate mesDeviceOeeCate) {
+		mesDeviceOeeCateService.save(mesDeviceOeeCate);
+		return renderResult(Global.TRUE, text("保存设备OEE阶段成功!"));
+	}
+	
+	/**
+	 * 停用数据
+	 */
+	@RequiresPermissions("mes:mesDeviceOeeCate:edit")
+	@RequestMapping(value = "disable")
+	@ResponseBody
+	public String disable(MesDeviceOeeCate mesDeviceOeeCate) {
+		mesDeviceOeeCate.setStatus(MesDeviceOeeCate.STATUS_DISABLE);
+		mesDeviceOeeCateService.updateStatus(mesDeviceOeeCate);
+		return renderResult(Global.TRUE, text("停用设备OEE阶段成功"));
+	}
+	
+	/**
+	 * 启用数据
+	 */
+	@RequiresPermissions("mes:mesDeviceOeeCate:edit")
+	@RequestMapping(value = "enable")
+	@ResponseBody
+	public String enable(MesDeviceOeeCate mesDeviceOeeCate) {
+		mesDeviceOeeCate.setStatus(MesDeviceOeeCate.STATUS_NORMAL);
+		mesDeviceOeeCateService.updateStatus(mesDeviceOeeCate);
+		return renderResult(Global.TRUE, text("启用设备OEE阶段成功"));
+	}
+	
+	/**
+	 * 删除数据
+	 */
+	@RequiresPermissions("mes:mesDeviceOeeCate:edit")
+	@RequestMapping(value = "delete")
+	@ResponseBody
+	public String delete(MesDeviceOeeCate mesDeviceOeeCate) {
+		mesDeviceOeeCateService.delete(mesDeviceOeeCate);
+		return renderResult(Global.TRUE, text("删除设备OEE阶段成功!"));
+	}
+	
+}

+ 249 - 0
src/main/java/com/jeesite/modules/mes/web/MesDeviceOeeController.java

@@ -0,0 +1,249 @@
+package com.jeesite.modules.mes.web;
+
+import com.jeesite.common.collect.ListUtils;
+import com.jeesite.common.collect.MapUtils;
+import com.jeesite.common.config.Global;
+import com.jeesite.common.entity.Page;
+import com.jeesite.common.lang.DateUtils;
+import com.jeesite.common.utils.excel.ExcelExport;
+import com.jeesite.common.utils.excel.annotation.ExcelField.Type;
+import com.jeesite.common.web.BaseController;
+import com.jeesite.modules.mes.entity.MesDeviceFault;
+import com.jeesite.modules.mes.entity.MesDeviceOee;
+import com.jeesite.modules.mes.entity.MesDeviceOeeCate;
+import com.jeesite.modules.mes.resp.CommonResp;
+import com.jeesite.modules.mes.service.MesDeviceFaultCateService;
+import com.jeesite.modules.mes.service.MesDeviceFaultMaintainService;
+import com.jeesite.modules.mes.service.MesDeviceOeeCateService;
+import com.jeesite.modules.mes.service.MesDeviceOeeService;
+import com.jeesite.modules.mes.util.CommonUitl;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * OEEController
+ * @author mes
+ * @version 2024-08-02
+ */
+@Controller
+@RequestMapping(value = "${adminPath}/mes/mesDeviceOee")
+public class MesDeviceOeeController extends BaseController {
+
+	@Autowired
+	private MesDeviceOeeService mesDeviceOeeService;
+	@Autowired
+	private MesDeviceFaultMaintainService mesDeviceFaultMaintainService;
+	@Autowired
+	private MesDeviceFaultCateService mesDeviceFaultCateService;
+
+	@Autowired
+	private MesDeviceOeeCateService mesDeviceOeeCateService;
+
+	/**
+	 * 获取数据
+	 */
+	@ModelAttribute
+	public MesDeviceOee get(String id, boolean isNewRecord) {
+		return mesDeviceOeeService.get(id, isNewRecord);
+	}
+	
+	/**
+	 * 查询列表
+	 */
+	@RequiresPermissions("mes:mesDeviceOee:view")
+	@RequestMapping(value = {"list", ""})
+	public String list(MesDeviceOee mesDeviceOee, Model model) {
+		model.addAttribute("mesDeviceOee", mesDeviceOee);
+		MesDeviceOeeCate mesDeviceOeeCate = new MesDeviceOeeCate();
+		mesDeviceOeeCate.setStatus("0");
+		model.addAttribute("mesDeviceOeeCate", mesDeviceOeeCateService.findList(mesDeviceOeeCate));
+		return "modules/mes/mesDeviceOeeList";
+	}
+	
+	/**
+	 * 查询列表数据
+	 */
+	@RequiresPermissions("mes:mesDeviceOee:view")
+	@RequestMapping(value = "listData")
+	@ResponseBody
+	public Page<MesDeviceOee> listData(MesDeviceOee mesDeviceOee, HttpServletRequest request, HttpServletResponse response) {
+		mesDeviceOee.setPage(new Page<>(request, response));
+		Page<MesDeviceOee> page = mesDeviceOeeService.findPage(mesDeviceOee);
+		return page;
+	}
+
+	/**
+	 * 查看编辑表单
+	 */
+	@RequiresPermissions("mes:mesDeviceOee:view")
+	@RequestMapping(value = "form")
+	public String form(MesDeviceOee mesDeviceOee, Model model) {
+		model.addAttribute("mesDeviceOee", mesDeviceOee);
+		MesDeviceOeeCate mesDeviceOeeCate = new MesDeviceOeeCate();
+		mesDeviceOeeCate.setStatus("0");
+		model.addAttribute("mesDeviceOeeCate", mesDeviceOeeCateService.findList(mesDeviceOeeCate));
+		return "modules/mes/mesDeviceOeeForm";
+	}
+
+	/**
+	 * 保存数据
+	 */
+	@RequiresPermissions("mes:mesDeviceOee:edit")
+	@PostMapping(value = "save")
+	@ResponseBody
+	public String save(@Validated MesDeviceOee mesDeviceOee) {
+		if (mesDeviceOee.getIsNewRecord() == true) {
+			MesDeviceOee mesDeviceOee1 = mesDeviceOeeService.findByDateAndtitle(mesDeviceOee);
+			if (mesDeviceOee1 != null) {
+				return renderResult(Global.TRUE, text("保存OEE失败,该记录已经存在!"));
+			}
+		}
+		mesDeviceOeeService.save(mesDeviceOee);
+		return renderResult(Global.TRUE, text("保存OEE成功!"));
+	}
+
+	/**
+	 * 导出数据
+	 */
+	@RequiresPermissions("mes:mesDeviceOee:view")
+	@RequestMapping(value = "exportData")
+	public void exportData(MesDeviceOee mesDeviceOee, HttpServletResponse response) {
+		List<MesDeviceOee> list = mesDeviceOeeService.findList(mesDeviceOee);
+		String fileName = "OEE" + DateUtils.getDate("yyyyMMddHHmmss") + ".xlsx";
+		try(ExcelExport ee = new ExcelExport("OEE", MesDeviceOee.class)){
+			ee.setDataList(list).write(response, fileName);
+		}
+	}
+
+	/**
+	 * 下载模板
+	 */
+	@RequiresPermissions("mes:mesDeviceOee:view")
+	@RequestMapping(value = "importTemplate")
+	public void importTemplate(HttpServletResponse response) {
+		MesDeviceOee mesDeviceOee = new MesDeviceOee();
+		List<MesDeviceOee> list = ListUtils.newArrayList(mesDeviceOee);
+		String fileName = "OEE模板.xlsx";
+		try(ExcelExport ee = new ExcelExport("OEE", MesDeviceOee.class, Type.IMPORT)){
+			ee.setDataList(list).write(response, fileName);
+		}
+	}
+
+	/**
+	 * 导入数据
+	 */
+	@ResponseBody
+	@RequiresPermissions("mes:mesDeviceOee:edit")
+	@PostMapping(value = "importData")
+	public String importData(MultipartFile file) {
+		try {
+			String message = mesDeviceOeeService.importData(file);
+			return renderResult(Global.TRUE, "posfull:"+message);
+		} catch (Exception ex) {
+			return renderResult(Global.FALSE, "posfull:"+ex.getMessage());
+		}
+	}
+	
+	/**
+	 * 删除数据
+	 */
+	@RequiresPermissions("mes:mesDeviceOee:edit")
+	@RequestMapping(value = "delete")
+	@ResponseBody
+	public String delete(MesDeviceOee mesDeviceOee) {
+		mesDeviceOeeService.delete(mesDeviceOee);
+		return renderResult(Global.TRUE, text("删除OEE成功!"));
+	}
+	@RequiresPermissions("mes:mesDeviceOee:view")
+	@RequestMapping(value = "tj")
+	public String tj(MesDeviceFault mesDeviceFault, Model model) {
+		LocalDate today = LocalDate.now();
+		MesDeviceOee mesDeviceOee = new MesDeviceOee();
+		mesDeviceOee.setStatus("0");
+
+		mesDeviceOee.setSdate(CommonUitl.String2Date(today.toString()));
+		mesDeviceOee.setEdate(CommonUitl.String2Date(today.toString()));
+
+		model.addAttribute("mesDeviceOee", mesDeviceOee);
+		return "modules/mes/mesDeviceOeeTj";
+	}
+
+	@RequestMapping(value = "tjData5")
+	@ResponseBody
+	public CommonResp tjData5(HttpServletRequest request) {
+		CommonResp<Map<String, Object>> resp = new CommonResp<>();
+
+
+		String sdate = request.getParameter("sdate");
+		String edate = request.getParameter("edate");
+		List<String> dates = CommonUitl.getDayList(sdate, edate);
+
+		Map<String, Object> map = MapUtils.newHashMap();
+
+
+		MesDeviceOeeCate mesDeviceOeeCate = new MesDeviceOeeCate();
+		List<MesDeviceOeeCate> list = mesDeviceOeeCateService.findList(mesDeviceOeeCate);
+
+		//X轴 所有故障工序
+		List<String> listTitle = new ArrayList<>();
+		//Y轴 所有故障工序的OEE
+		List<Double> listOEE = new ArrayList<>();
+
+		for (MesDeviceOeeCate dtl : list) {
+			listTitle.add(dtl.getTitle());
+			double totalOee = 0.0;
+			for (String date:dates){
+				double oee = getOeeDate(dtl,date);
+				totalOee += oee;
+			}
+
+
+			double oee = new BigDecimal(totalOee/dates.size()).setScale(2, RoundingMode.HALF_UP).doubleValue();
+			listOEE.add(oee);
+		}
+
+		map.put("titles", listTitle);
+		map.put("oees", listOEE);
+
+		resp.setData(map);
+		resp.setResult(Global.TRUE);
+		return resp;
+	}
+
+
+	private double getOeeDate(MesDeviceOeeCate dtl,String date){
+		double oee = 0.0;
+		MesDeviceOee mesDeviceOee2 = new MesDeviceOee();
+		mesDeviceOee2.setCateId(dtl.getId());
+		mesDeviceOee2.setDate(CommonUitl.String2Date2(date));
+		MesDeviceOee mesDeviceOee1 = mesDeviceOeeService.findByDateAndtitle(mesDeviceOee2);
+		if (mesDeviceOee1 == null) {
+			return oee;
+		}
+		//计划产量
+		Integer planNum = mesDeviceOee1.getPlanNum();
+		//当日产量
+		Integer todayNum = mesDeviceOee1.getTodayNum();
+		if (planNum == null || todayNum == null || planNum == 0 || todayNum == 0) {
+			return oee;
+		}
+		return new BigDecimal((double) todayNum / planNum * 100).setScale(2, RoundingMode.HALF_UP).doubleValue();
+	}
+}

+ 51 - 17
src/main/java/com/jeesite/modules/mes/web/MesDevicePreventTaskController.java

@@ -83,16 +83,13 @@ public class MesDevicePreventTaskController extends BaseController {
 	}
 
 	/**
-	 * 我的计划
+	 * 预防性维护记录(展示全部记录,不按当前用户过滤)
 	 */
 	@RequiresPermissions("mes:mesDevicePreventTask:view")
 	@RequestMapping(value = {"mylist", ""})
 	public String mylist(MesDevicePreventTask mesDevicePreventTask, Model model) {
-		User user = UserUtils.getUser();
-		// 标记为我的计划查询,listData 中按关系表过滤
-		mesDevicePreventTask.setUserCode(user.getUserCode());
+		mesDevicePreventTask.setUserCode(null);
 		model.addAttribute("mesDevicePreventTask", mesDevicePreventTask);
-		model.addAttribute("myTaskOnly", true);
 		return "modules/mes/mesDevicePreventTaskMyList";
 	}
 	
@@ -104,17 +101,56 @@ public class MesDevicePreventTaskController extends BaseController {
 	@ResponseBody
 	public Page<MesDevicePreventTask> listData(MesDevicePreventTask mesDevicePreventTask, HttpServletRequest request, HttpServletResponse response) {
 		mesDevicePreventTask.setPage(new Page<>(request, response));
-		// 我的计划:按执行人关系表过滤(兼容原有传 userCode 的方式)
-		String myTaskOnly = request.getParameter("myTaskOnly");
-		if (Global.TRUE.equals(myTaskOnly) || "1".equals(myTaskOnly) || "true".equalsIgnoreCase(myTaskOnly)) {
-			User user = UserUtils.getUser();
-			mesDevicePreventTaskService.applyAssigneeFilter(mesDevicePreventTask, user.getUserCode());
-		}
 		Page<MesDevicePreventTask> page = mesDevicePreventTaskService.findPage(mesDevicePreventTask);
 		return page;
 	}
 
 	/**
+	 * 维护计划一级:按批次汇总,一行一份计划
+	 */
+	@RequiresPermissions("mes:mesDevicePreventTask:view")
+	@RequestMapping(value = "planListData")
+	@ResponseBody
+	public Page<MesDevicePreventTask> planListData(MesDevicePreventTask mesDevicePreventTask, HttpServletRequest request, HttpServletResponse response) {
+		Page<MesDevicePreventTask> page = new Page<>(request, response);
+		mesDevicePreventTask.setPage(page);
+		mesDevicePreventTask.getSqlMap().getOrder().setOrderBy("");
+		return mesDevicePreventTaskService.findPlanPage(mesDevicePreventTask);
+	}
+
+	/**
+	 * 维护计划二级:某一批次下的各期任务
+	 */
+	@RequiresPermissions("mes:mesDevicePreventTask:view")
+	@RequestMapping(value = "planChildData")
+	@ResponseBody
+	public Page<MesDevicePreventTask> planChildData(MesDevicePreventTask mesDevicePreventTask, HttpServletRequest request, HttpServletResponse response) {
+		if (StringUtils.isBlank(mesDevicePreventTask.getBatchId())) {
+			Page<MesDevicePreventTask> empty = new Page<>(request, response);
+			empty.setList(new ArrayList<MesDevicePreventTask>());
+			empty.setCount(0);
+			return empty;
+		}
+		mesDevicePreventTask.setPage(new Page<>(request, response));
+		mesDevicePreventTask.getSqlMap().getOrder().setOrderBy("a.start_date ASC");
+		return mesDevicePreventTaskService.findPage(mesDevicePreventTask);
+	}
+
+	/**
+	 * 删除同一批次下的全部周期任务
+	 */
+	@RequiresPermissions("mes:mesDevicePreventTask:edit")
+	@RequestMapping(value = "deleteBatch")
+	@ResponseBody
+	public String deleteBatch(String batchId) {
+		if (StringUtils.isBlank(batchId)) {
+			return renderResult(Global.FALSE, text("未找到维护计划!"));
+		}
+		mesDevicePreventTaskService.deleteByBatch(batchId);
+		return renderResult(Global.TRUE, text("删除维护计划成功!"));
+	}
+
+	/**
 	 * 查看编辑表单
 	 */
 	@RequiresPermissions("mes:mesDevicePreventTask:view")
@@ -365,16 +401,14 @@ public class MesDevicePreventTaskController extends BaseController {
 		}
 	}
 	/**
-	 * 导出数据(我的维修计划)
+	 * 导出数据(预防性维护记录,不按当前用户过滤)
 	 */
 	@RequestMapping(value = "exportData2")
-	public void exportData2(MesDevicePreventTask mesDevicePreventTask, HttpServletRequest request, HttpServletResponse response) {
-		User user = UserUtils.getUser();
-		mesDevicePreventTaskService.applyAssigneeFilter(mesDevicePreventTask, user.getUserCode());
+	public void exportData2(MesDevicePreventTask mesDevicePreventTask, HttpServletResponse response) {
 		List<MesDevicePreventTask> list = mesDevicePreventTaskService.findList(mesDevicePreventTask);
 		List<ExcelMesDevicePreventTask> list1 = BeanUtil.copyToList(list, ExcelMesDevicePreventTask.class);
-		String fileName = "我的维修计划" + DateUtils.getDate("yyyyMMddHHmmss") + ".xlsx";
-		try(ExcelExport ee = new ExcelExport("我的维修计划", ExcelMesDevicePreventTask.class)){
+		String fileName = "预防性维护记录" + DateUtils.getDate("yyyyMMddHHmmss") + ".xlsx";
+		try(ExcelExport ee = new ExcelExport("预防性维护记录", ExcelMesDevicePreventTask.class)){
 			ee.setDataList(list1).write(response, fileName);
 		}
 	}

+ 153 - 0
src/main/java/com/jeesite/modules/mes/web/MesDeviceVulnerableController.java

@@ -0,0 +1,153 @@
+package com.jeesite.modules.mes.web;
+
+import java.util.List;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import com.jeesite.modules.file.utils.FileUploadUtils;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.jeesite.common.config.Global;
+import com.jeesite.common.collect.ListUtils;
+import com.jeesite.common.entity.Page;
+import com.jeesite.common.lang.DateUtils;
+import com.jeesite.common.utils.excel.ExcelExport;
+import com.jeesite.common.utils.excel.annotation.ExcelField.Type;
+import org.springframework.web.multipart.MultipartFile;
+import com.jeesite.common.web.BaseController;
+import com.jeesite.modules.mes.entity.MesDeviceVulnerable;
+import com.jeesite.modules.mes.service.MesDeviceVulnerableService;
+
+/**
+ * 产线设备易损件清单Controller
+ * @author mes
+ * @version 2024-08-05
+ */
+@Controller
+@RequestMapping(value = "${adminPath}/mes/mesDeviceVulnerable")
+public class MesDeviceVulnerableController extends BaseController {
+
+	@Autowired
+	private MesDeviceVulnerableService mesDeviceVulnerableService;
+	
+	/**
+	 * 获取数据
+	 */
+	@ModelAttribute
+	public MesDeviceVulnerable get(String id, boolean isNewRecord) {
+		return mesDeviceVulnerableService.get(id, isNewRecord);
+	}
+	
+	/**
+	 * 查询列表
+	 */
+	@RequiresPermissions("mes:mesDeviceVulnerable:view")
+	@RequestMapping(value = {"list", ""})
+	public String list(MesDeviceVulnerable mesDeviceVulnerable, Model model) {
+		model.addAttribute("mesDeviceVulnerable", mesDeviceVulnerable);
+		return "modules/mes/mesDeviceVulnerableList";
+	}
+	
+	/**
+	 * 查询列表数据
+	 */
+	@RequiresPermissions("mes:mesDeviceVulnerable:view")
+	@RequestMapping(value = "listData")
+	@ResponseBody
+	public Page<MesDeviceVulnerable> listData(MesDeviceVulnerable mesDeviceVulnerable, HttpServletRequest request, HttpServletResponse response) {
+		mesDeviceVulnerable.setPage(new Page<>(request, response));
+		Page<MesDeviceVulnerable> page = mesDeviceVulnerableService.findPage(mesDeviceVulnerable);
+		return page;
+	}
+
+	/**
+	 * 查看编辑表单
+	 */
+	@RequiresPermissions("mes:mesDeviceVulnerable:view")
+	@RequestMapping(value = "form")
+	public String form(MesDeviceVulnerable mesDeviceVulnerable, Model model) {
+		model.addAttribute("mesDeviceVulnerable", mesDeviceVulnerable);
+		return "modules/mes/mesDeviceVulnerableForm";
+	}
+
+	/**
+	 * 保存数据
+	 */
+	@RequiresPermissions("mes:mesDeviceVulnerable:edit")
+	@PostMapping(value = "save")
+	@ResponseBody
+	public String save(@Validated MesDeviceVulnerable mesDeviceVulnerable) {
+		mesDeviceVulnerableService.save(mesDeviceVulnerable);
+		FileUploadUtils.saveFileUpload(mesDeviceVulnerable, mesDeviceVulnerable.getId(), "mesDeviceVulnerable_image");
+		return renderResult(Global.TRUE, text("保存产线设备易损件清单成功!"));
+	}
+
+	/**
+	 * 导出数据
+	 */
+	@RequiresPermissions("mes:mesDeviceVulnerable:view")
+	@RequestMapping(value = "exportData")
+	public void exportData(MesDeviceVulnerable mesDeviceVulnerable, HttpServletResponse response) {
+		List<MesDeviceVulnerable> list = mesDeviceVulnerableService.findList(mesDeviceVulnerable);
+		String fileName = "产线设备易损件清单" + DateUtils.getDate("yyyyMMddHHmmss") + ".xlsx";
+		try(ExcelExport ee = new ExcelExport("产线设备易损件清单", MesDeviceVulnerable.class)){
+			ee.setDataList(list).write(response, fileName);
+		}
+	}
+
+	/**
+	 * 下载模板
+	 */
+	@RequiresPermissions("mes:mesDeviceVulnerable:view")
+	@RequestMapping(value = "importTemplate")
+	public void importTemplate(HttpServletResponse response) {
+		MesDeviceVulnerable mesDeviceVulnerable = new MesDeviceVulnerable();
+		List<MesDeviceVulnerable> list = ListUtils.newArrayList(mesDeviceVulnerable);
+		String fileName = "产线设备易损件清单模板.xlsx";
+		try(ExcelExport ee = new ExcelExport("产线设备易损件清单", MesDeviceVulnerable.class, Type.IMPORT)){
+			ee.setDataList(list).write(response, fileName);
+		}
+	}
+
+	/**
+	 * 导入数据
+	 */
+	@ResponseBody
+	@RequiresPermissions("mes:mesDeviceVulnerable:edit")
+	@PostMapping(value = "importData")
+	public String importData(MultipartFile file) {
+		try {
+			String message = mesDeviceVulnerableService.importData(file);
+			return renderResult(Global.TRUE, "posfull:"+message);
+		} catch (Exception ex) {
+			return renderResult(Global.FALSE, "posfull:"+ex.getMessage());
+		}
+	}
+	
+	/**
+	 * 删除数据
+	 */
+	@RequiresPermissions("mes:mesDeviceVulnerable:edit")
+	@RequestMapping(value = "delete")
+	@ResponseBody
+	public String delete(MesDeviceVulnerable mesDeviceVulnerable) {
+		mesDeviceVulnerableService.delete(mesDeviceVulnerable);
+		return renderResult(Global.TRUE, text("删除产线设备易损件清单成功!"));
+	}
+
+
+	@RequestMapping(value = "detail")
+	public String detail(MesDeviceVulnerable mesDeviceVulnerable, Model model) {
+		model.addAttribute("mesDeviceVulnerable", mesDeviceVulnerable);
+		return "modules/mes/mesDeviceVulnerableDetail";
+	}
+	
+}

+ 1 - 1
src/main/resources/config/application.yml

@@ -130,7 +130,7 @@ erp:
       default-dest-stock-number:
     # 生产入库单 PRD_INSTOCK 查询(固定 HEV / 115 物料,与直接调拨单一致)
     prd-in-stock:
-      material-numbers: 8.10.HEV.10.047696,8.10.HEV.10.049025,8.35.115.10.5003146600021
+      material-numbers: 8.10.HEV.10.047696,8.10.HEV.10.049025,8.10.HEV.05.047696,8.10.HEV.05.049025,8.35.115.10.5003146600021
       # Save 配置(单据类型/入库类型需与 ERP 账套一致,Save 报错时可调整)
       bill-type: SCRKD01_SYS
       in-stock-type: "1"

+ 18 - 0
src/main/resources/mappings/modules/mes/MesDeviceFaultCateDao.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jeesite.modules.mes.dao.MesDeviceFaultCateDao">
+	
+	<!-- 查询数据
+	<select id="findList" resultType="MesDeviceFaultCate">
+		SELECT ${sqlMap.column.toSql()}
+		FROM ${sqlMap.table.toSql()}
+		<where>
+			${sqlMap.where.toSql()}
+		</where>
+		ORDER BY ${sqlMap.order.toSql()}
+	</select> -->
+
+	<select id="findByTitle" resultType="com.jeesite.modules.mes.entity.MesDeviceFaultCate">
+		select  * from mes_device_fault_cate where title = #{title}
+	</select>
+</mapper>

+ 15 - 0
src/main/resources/mappings/modules/mes/MesDeviceFaultDao.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jeesite.modules.mes.dao.MesDeviceFaultDao">
+	
+	<!-- 查询数据
+	<select id="findList" resultType="MesDeviceFault">
+		SELECT ${sqlMap.column.toSql()}
+		FROM ${sqlMap.table.toSql()}
+		<where>
+			${sqlMap.where.toSql()}
+		</where>
+		ORDER BY ${sqlMap.order.toSql()}
+	</select> -->
+	
+</mapper>

+ 17 - 0
src/main/resources/mappings/modules/mes/MesDeviceFaultMaintainDao.xml

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jeesite.modules.mes.dao.MesDeviceFaultMaintainDao">
+	
+	<!-- 查询数据
+	<select id="findList" resultType="MesDeviceFaultMaintain">
+		SELECT ${sqlMap.column.toSql()}
+		FROM ${sqlMap.table.toSql()}
+		<where>
+			${sqlMap.where.toSql()}
+		</where>
+		ORDER BY ${sqlMap.order.toSql()}
+	</select> -->
+	<select id="findByTitle" resultType="com.jeesite.modules.mes.entity.MesDeviceFaultMaintain">
+		select  * from mes_device_fault_maintain where title = #{title}
+	</select>
+</mapper>

+ 15 - 0
src/main/resources/mappings/modules/mes/MesDeviceOeeCateDao.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jeesite.modules.mes.dao.MesDeviceOeeCateDao">
+	
+	<!-- 查询数据
+	<select id="findList" resultType="MesDeviceOeeCate">
+		SELECT ${sqlMap.column.toSql()}
+		FROM ${sqlMap.table.toSql()}
+		<where>
+			${sqlMap.where.toSql()}
+		</where>
+		ORDER BY ${sqlMap.order.toSql()}
+	</select> -->
+	
+</mapper>

+ 18 - 0
src/main/resources/mappings/modules/mes/MesDeviceOeeDao.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jeesite.modules.mes.dao.MesDeviceOeeDao">
+	
+	<!-- 查询数据
+	<select id="findList" resultType="MesDeviceOee">
+		SELECT ${sqlMap.column.toSql()}
+		FROM ${sqlMap.table.toSql()}
+		<where>
+			${sqlMap.where.toSql()}
+		</where>
+		ORDER BY ${sqlMap.order.toSql()}
+	</select> -->
+
+    <select id="findByDateAndtitle" resultType="com.jeesite.modules.mes.entity.MesDeviceOee">
+        SELECT * FROM mes_device_oee WHERE date = #{date} AND cate_id = #{cateId}
+    </select>
+</mapper>

+ 50 - 0
src/main/resources/mappings/modules/mes/MesDevicePreventTaskDao.xml

@@ -11,5 +11,55 @@
 		</where>
 		ORDER BY ${sqlMap.order.toSql()}
 	</select> -->
+
+	<!-- 一级:同一批次只出一行,避免周期任务把列表撑满 -->
+	<select id="findPlanList" resultType="com.jeesite.modules.mes.entity.MesDevicePreventTask">
+		SELECT
+			a.batch_id AS "id",
+			a.batch_id AS "batchId",
+			MAX(a.prevent_id) AS "preventId",
+			MAX(b.title) AS "preventTitle",
+			MAX(a.device_id) AS "deviceId",
+			MAX(c.tree_name) AS "deviceName",
+			MAX(a.user_code) AS "userCode",
+			MIN(a.start_date) AS "startDate",
+			MAX(a.end_date) AS "endDate",
+			CAST(COUNT(1) AS SIGNED) AS "taskCount",
+			CAST(SUM(CASE WHEN a.state = '1' THEN 1 ELSE 0 END) AS SIGNED) AS "doneCount",
+			(
+				SELECT DATEDIFF(n.start_date, t.start_date)
+				FROM mes_device_prevent_task t
+				INNER JOIN mes_device_prevent_task n
+					ON n.batch_id = t.batch_id AND n.start_date > t.start_date
+				WHERE t.batch_id = a.batch_id
+					AND NOT EXISTS (
+						SELECT 1 FROM mes_device_prevent_task m
+						WHERE m.batch_id = t.batch_id
+							AND m.start_date > t.start_date
+							AND m.start_date &lt; n.start_date
+					)
+				ORDER BY t.start_date
+				LIMIT 1
+			) AS "cycleDays"
+		FROM mes_device_prevent_task a
+		LEFT JOIN mes_device_prevent b ON b.id = a.prevent_id
+		LEFT JOIN mes_device c ON c.tree_code = a.device_id
+		<where>
+			${sqlMap.where.toSql()}
+		</where>
+		GROUP BY a.batch_id
+		ORDER BY MAX(a.update_date) DESC, a.batch_id DESC
+	</select>
+
+	<select id="findPlanCount" resultType="long">
+		SELECT COUNT(1) FROM (
+			SELECT a.batch_id
+			FROM mes_device_prevent_task a
+			<where>
+				${sqlMap.where.toSql()}
+			</where>
+			GROUP BY a.batch_id
+		) t
+	</select>
 	
 </mapper>

+ 15 - 0
src/main/resources/mappings/modules/mes/MesDeviceVulnerableDao.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jeesite.modules.mes.dao.MesDeviceVulnerableDao">
+	
+	<!-- 查询数据
+	<select id="findList" resultType="MesDeviceVulnerable">
+		SELECT ${sqlMap.column.toSql()}
+		FROM ${sqlMap.table.toSql()}
+		<where>
+			${sqlMap.where.toSql()}
+		</where>
+		ORDER BY ${sqlMap.order.toSql()}
+	</select> -->
+	
+</mapper>

+ 66 - 0
src/main/resources/views/modules/mes/mesDeviceFaultCateForm.html

@@ -0,0 +1,66 @@
+<% layout('/layouts/default.html', {title: '设备故障分类管理', libs: ['validate']}){ %>
+<div class="main-content">
+	<div class="box box-main">
+		<div class="box-header with-border">
+			<div class="box-title">
+				<i class="fa icon-note"></i> ${text(mesDeviceFaultCate.isNewRecord ? '新增设备故障分类' : '编辑设备故障分类')}
+			</div>
+			<div class="box-tools pull-right">
+				<button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>
+			</div>
+		</div>
+		<#form:form id="inputForm" model="${mesDeviceFaultCate}" action="${ctx}/mes/mesDeviceFaultCate/save" method="post" class="form-horizontal">
+			<div class="box-body">
+				<div class="form-unit">${text('基本信息')}</div>
+				<#form:hidden path="id"/>
+				<div class="row">
+					<div class="col-xs-12">
+						<div class="form-group">
+							<label class="control-label col-sm-2" title="">
+								<span class="required ">*</span> ${text('名称')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-4">
+								<#form:input path="title" maxlength="255" class="form-control required"/>
+							</div>
+						</div>
+					</div>
+				</div>
+				<div class="row">
+					<div class="col-xs-12">
+						<div class="form-group">
+							<label class="control-label col-sm-2" title="">
+								<span class="required hide">*</span> ${text('备注')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-4">
+								<#form:input path="remark" maxlength="255" class="form-control"/>
+							</div>
+						</div>
+					</div>
+				</div>
+			</div>
+			<div class="box-footer">
+				<div class="row">
+					<div class="col-sm-offset-2 col-sm-10">
+						<% if (hasPermi('mes:mesDeviceFaultCate:edit')){ %>
+							<button type="submit" class="btn btn-sm btn-primary" id="btnSubmit"><i class="fa fa-check"></i> ${text('保 存')}</button>&nbsp;
+						<% } %>
+						<button type="button" class="btn btn-sm btn-default" id="btnCancel" onclick="js.closeCurrentTabPage()"><i class="fa fa-reply-all"></i> ${text('关 闭')}</button>
+					</div>
+				</div>
+			</div>
+		</#form:form>
+	</div>
+</div>
+<% } %>
+<script>
+$("#inputForm").validate({
+	submitHandler: function(form){
+		js.ajaxSubmitForm($(form), function(data){
+			js.showMessage(data.message);
+			if(data.result == Global.TRUE){
+				js.closeCurrentTabPage(function(contentWindow){
+					contentWindow.page();
+				});
+			}
+		}, "json");
+    }
+});
+</script>

+ 80 - 0
src/main/resources/views/modules/mes/mesDeviceFaultCateList.html

@@ -0,0 +1,80 @@
+<% layout('/layouts/default.html', {title: '设备故障分类管理', libs: ['dataGrid']}){ %>
+<div class="main-content">
+	<div class="box box-main">
+		<div class="box-header">
+			<div class="box-title">
+				<i class="fa icon-notebook"></i> ${text('设备故障分类管理')}
+			</div>
+			<div class="box-tools pull-right">
+				<a href="#" class="btn btn-default" id="btnSearch" title="${text('查询')}"><i class="fa fa-filter"></i> ${text('查询')}</a>
+				<% if(hasPermi('mes:mesDeviceFaultCate:edit')){ %>
+					<a href="${ctx}/mes/mesDeviceFaultCate/form" class="btn btn-default btnTool" title="${text('新增设备故障分类')}"><i class="fa fa-plus"></i> ${text('新增')}</a>
+				<% } %>
+				<a href="#" class="btn btn-default" id="btnSetting" title="${text('设置')}"><i class="fa fa-navicon"></i></a>
+			</div>
+		</div>
+		<div class="box-body">
+			<#form:form id="searchForm" model="${mesDeviceFaultCate}" action="${ctx}/mes/mesDeviceFaultCate/listData" method="post" class="form-inline hide"
+					data-page-no="${parameter.pageNo}" data-page-size="${parameter.pageSize}" data-order-by="${parameter.orderBy}">
+				<div class="form-group">
+					<label class="control-label">${text('名称')}:</label>
+					<div class="control-inline">
+						<#form:input path="title" maxlength="255" class="form-control width-120"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('备注')}:</label>
+					<div class="control-inline">
+						<#form:input path="remark" maxlength="255" class="form-control width-120"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('状态')}:</label>
+					<div class="control-inline width-120">
+						<#form:select path="status" dictType="sys_search_status" blankOption="true" class="form-control isQuick"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<button type="submit" class="btn btn-primary btn-sm">${text('查询')}</button>
+					<button type="reset" class="btn btn-default btn-sm">${text('重置')}</button>
+				</div>
+			</#form:form>
+			<table id="dataGrid"></table>
+			<div id="dataGridPage"></div>
+		</div>
+	</div>
+</div>
+<% } %>
+<script>
+// 初始化DataGrid对象
+$('#dataGrid').dataGrid({
+	searchForm: $("#searchForm"),
+	columnModel: [
+		{header:'${text("名称")}', name:'title', index:'a.title', width:150, align:"center", frozen:true, formatter: function(val, obj, row, act){
+			return '<a href="${ctx}/mes/mesDeviceFaultCate/form?id='+row.id+'" class="btnList" data-title="${text("编辑设备故障分类")}">'+(val||row.id)+'</a>';
+		}},
+		{header:'${text("备注")}', name:'remark', index:'a.remark', width:150, align:"center"},
+		{header:'${text("状态")}', name:'status', index:'a.status', width:150, align:"center", formatter: function(val, obj, row, act){
+			return js.getDictLabel(${@DictUtils.getDictListJson('sys_search_status')}, val, '${text("未知")}', true);
+		}},
+		{header:'${text("更新时间")}', name:'updateDate', index:'a.update_date', width:150, align:"center"},
+		{header:'${text("操作")}', name:'actions', width:120, formatter: function(val, obj, row, act){
+			var actions = [];
+			//<% if(hasPermi('mes:mesDeviceFaultCate:edit')){ %>
+				actions.push('<a href="${ctx}/mes/mesDeviceFaultCate/form?id='+row.id+'" class="btnList" title="${text("编辑设备故障分类")}"><i class="fa fa-pencil"></i></a>&nbsp;');
+				if (row.status == Global.STATUS_NORMAL){
+					actions.push('<a href="${ctx}/mes/mesDeviceFaultCate/disable?id='+row.id+'" class="btnList" title="${text("停用设备故障分类")}" data-confirm="${text("确认要停用该设备故障分类吗?")}"><i class="glyphicon glyphicon-ban-circle"></i></a>&nbsp;');
+				} else if (row.status == Global.STATUS_DISABLE){
+					actions.push('<a href="${ctx}/mes/mesDeviceFaultCate/enable?id='+row.id+'" class="btnList" title="${text("启用设备故障分类")}" data-confirm="${text("确认要启用该设备故障分类吗?")}"><i class="glyphicon glyphicon-ok-circle"></i></a>&nbsp;');
+				}
+				actions.push('<a href="${ctx}/mes/mesDeviceFaultCate/delete?id='+row.id+'" class="btnList" title="${text("删除设备故障分类")}" data-confirm="${text("确认要删除该设备故障分类吗?")}"><i class="fa fa-trash-o"></i></a>&nbsp;');
+			//<% } %>
+			return actions.join('');
+		}}
+	],
+	// 加载成功后执行事件
+	ajaxSuccess: function(data){
+		
+	}
+});
+</script>

+ 178 - 0
src/main/resources/views/modules/mes/mesDeviceFaultForm.html

@@ -0,0 +1,178 @@
+<% layout('/layouts/default.html', {title: '设备故障记录管理', libs: ['validate','fileupload']}){ %>
+<div class="main-content">
+	<div class="box box-main">
+		<div class="box-header with-border">
+			<div class="box-title">
+				<i class="fa icon-note"></i> ${text(mesDeviceFault.isNewRecord ? '新增设备故障记录' : '编辑设备故障记录')}
+			</div>
+			<div class="box-tools pull-right">
+				<button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>
+			</div>
+		</div>
+		<#form:form id="inputForm" model="${mesDeviceFault}" action="${ctx}/mes/mesDeviceFault/save" method="post" class="form-horizontal">
+			<div class="box-body">
+				<div class="form-unit">${text('基本信息')}</div>
+				<#form:hidden path="id"/>
+				<div class="row">
+<!--					<div class="col-xs-6">-->
+<!--						<div class="form-group">-->
+<!--							<label class="control-label col-sm-4" title="">-->
+<!--								<span class="required hide">*</span> ${text('工序')}:<i class="fa icon-question hide"></i></label>-->
+<!--							<div class="col-sm-8">-->
+<!--								<#form:input path="oprno" maxlength="255" class="form-control"/>-->
+<!--							</div>-->
+<!--						</div>-->
+<!--					</div>-->
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required ">*</span> ${text('故障工序')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:select  path="maintainId"  blankOption="true" items="${mesDeviceFaultMaintain}" itemLabel="title" itemValue="id" class="form-control required" />
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required hide">*</span> ${text('停台级别')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:select path="level" dictType="mes_device_fault_level" blankOption="true" class="form-control" />
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required hide">*</span> ${text('故障分类')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:select  path="cateId"  blankOption="true" items="${mesDeviceFaultCate}" itemLabel="title" itemValue="id" class="form-control required" />
+							</div>
+						</div>
+					</div>
+
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required hide">*</span> ${text('故障现象')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:input path="faultPhenomenon" maxlength="255" class="form-control"/>
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required hide">*</span> ${text('问题描述')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:textarea path="problemDescription" rows="4" maxlength="200" class="form-control"/>
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required hide">*</span> ${text('根因分析')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:textarea path="analysis" rows="4" maxlength="200" class="form-control"/>
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required hide">*</span> ${text('临时措施')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:textarea path="temporaryMeasures" rows="4" maxlength="200" class="form-control"/>
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required hide">*</span> ${text('根除措施')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:textarea path="eradicationMeasures" rows="4" maxlength="200" class="form-control"/>
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required hide">*</span> ${text('处理人')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:input path="handleBy" maxlength="255" class="form-control"/>
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required ">*</span> ${text('开始时间')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:input path="startDate" readonly="true" maxlength="20" class="form-control laydate required"
+									dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm"/>
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required hide">*</span> ${text('结束时间')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:input path="endDate" readonly="true" maxlength="20" class="form-control laydate"
+									dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm"/>
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required ">*</span> ${text('状态')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:select path="state" dictType="mes_device_fault_state" blankOption="true" class="form-control required"/>
+							</div>
+						</div>
+					</div>
+				</div>
+				<div class="row">
+					<div class="col-xs-12">
+						<div class="form-group">
+							<label class="control-label col-sm-2">
+								<span class="required hide">*</span> ${text('图片上传')}:</label>
+							<div class="col-sm-10">
+								<#form:fileupload id="uploadImage" bizKey="${mesDeviceFault.id}" bizType="mesDeviceFault_image"
+									uploadType="image" class="" readonly="false" preview="true"/>
+							</div>
+						</div>
+					</div>
+				</div>
+			</div>
+			<div class="box-footer">
+				<div class="row">
+					<div class="col-sm-offset-2 col-sm-10">
+						<% if (hasPermi('mes:mesDeviceFault:edit')){ %>
+							<button type="submit" class="btn btn-sm btn-primary" id="btnSubmit"><i class="fa fa-check"></i> ${text('保 存')}</button>&nbsp;
+						<% } %>
+						<button type="button" class="btn btn-sm btn-default" id="btnCancel" onclick="js.closeCurrentTabPage()"><i class="fa fa-reply-all"></i> ${text('关 闭')}</button>
+					</div>
+				</div>
+			</div>
+		</#form:form>
+	</div>
+</div>
+<% } %>
+<script>
+$("#inputForm").validate({
+	submitHandler: function(form){
+		js.ajaxSubmitForm($(form), function(data){
+			js.showMessage(data.message);
+			if(data.result == Global.TRUE){
+				js.closeCurrentTabPage(function(contentWindow){
+					contentWindow.page();
+				});
+			}
+		}, "json");
+    }
+});
+</script>

+ 209 - 0
src/main/resources/views/modules/mes/mesDeviceFaultList.html

@@ -0,0 +1,209 @@
+<% layout('/layouts/default.html', {title: '设备故障记录管理', libs: ['dataGrid']}){ %>
+<div class="main-content">
+	<div class="box box-main">
+		<div class="box-header">
+			<div class="box-title">
+				<i class="fa icon-notebook"></i> ${text('设备故障记录管理')}
+			</div>
+			<div class="box-tools pull-right">
+				<a href="#" class="btn btn-default" id="btnSearch" title="${text('查询')}"><i class="fa fa-filter"></i> ${text('查询')}</a>
+
+				<% if(hasPermi('mes:mesDeviceFault:edit')){ %>
+					<a href="${ctx}/mes/mesDeviceFault/form" class="btn btn-default btnTool" title="${text('新增设备故障记录')}"><i class="fa fa-fw fa-bar-chart"></i> ${text('新增')}</a>
+					<a href="#" class="btn btn-default" id="btnImport"><i class="glyphicon glyphicon-import"></i> 导入</a>
+				<% } %>
+				<a href="#" class="btn btn-default" id="btnExport"><i class="glyphicon glyphicon-export"></i> 导出</a>
+				<a href="${ctx}/mes/mesDeviceFault/tj" class="btn btn-default btnTool" title="${text('统计')}"><i class="fa fa-plus"></i> ${text('统计')}</a>
+				<a href="${ctx}/mes/mesDeviceFault/tj2" class="btn btn-default btnTool" title="${text('mttr/mtbf统计')}"><i class="fa fa-plus"></i> ${text('mttr/mtbf统计')}</a>
+				<a href="#" class="btn btn-default" id="btnSetting" title="${text('设置')}"><i class="fa fa-navicon"></i></a>
+			</div>
+		</div>
+		<div class="box-body">
+			<#form:form id="searchForm" model="${mesDeviceFault}" action="${ctx}/mes/mesDeviceFault/listData" method="post" class="form-inline hide"
+					data-page-no="${parameter.pageNo}" data-page-size="${parameter.pageSize}" data-order-by="${parameter.orderBy}">
+			<div class="form-group">
+				<label class="control-label">${text('故障工序')}:</label>
+				<div class="control-inline width-120">
+					<#form:select  path="maintainId"  blankOption="true" items="${mesDeviceFaultMaintain}" itemLabel="title" itemValue="id" class="form-control" />
+				</div>
+			</div>
+				<div class="form-group">
+					<label class="control-label">${text('停台级别')}:</label>
+					<div class="control-inline width-120">
+						<#form:select path="level" dictType="mes_device_fault_level" blankOption="true" class="form-control"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('故障分类')}:</label>
+					<div class="control-inline width-120">
+						<#form:select  path="cateId"  blankOption="true" items="${mesDeviceFaultCate}" itemLabel="title" itemValue="id" class="form-control" />
+					</div>
+				</div>
+
+				<div class="form-group">
+					<label class="control-label">${text('故障现象')}:</label>
+					<div class="control-inline">
+						<#form:input path="faultPhenomenon" maxlength="255" class="form-control width-120"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('问题描述')}:</label>
+					<div class="control-inline">
+						<#form:input path="problemDescription" maxlength="255" class="form-control width-120"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('根因分析')}:</label>
+					<div class="control-inline">
+						<#form:input path="analysis" maxlength="255" class="form-control width-120"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('临时措施')}:</label>
+					<div class="control-inline">
+						<#form:input path="temporaryMeasures" maxlength="255" class="form-control width-120"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('根除措施')}:</label>
+					<div class="control-inline">
+						<#form:input path="eradicationMeasures" maxlength="255" class="form-control width-120"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('处理人')}:</label>
+					<div class="control-inline">
+						<#form:input path="handleBy" maxlength="255" class="form-control width-120"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('开始时间')}:</label>
+					<div class="control-inline">
+						<#form:input path="startDate_gte" readonly="true" maxlength="20" class="form-control laydate width-datetime"
+							dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm" data-done="startDate_lte.click()"/>
+						&nbsp;-&nbsp;
+						<#form:input path="startDate_lte" readonly="true" maxlength="20" class="form-control laydate width-datetime"
+							dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('结束时间')}:</label>
+					<div class="control-inline">
+						<#form:input path="endDate_gte" readonly="true" maxlength="20" class="form-control laydate width-datetime"
+							dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm" data-done="endDate_lte.click()"/>
+						&nbsp;-&nbsp;
+						<#form:input path="endDate_lte" readonly="true" maxlength="20" class="form-control laydate width-datetime"
+							dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('状态')}:</label>
+					<div class="control-inline width-120">
+						<#form:select path="state" dictType="mes_device_fault_state" blankOption="true" class="form-control"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<button type="submit" class="btn btn-primary btn-sm">${text('查询')}</button>
+					<button type="reset" class="btn btn-default btn-sm">${text('重置')}</button>
+				</div>
+			</#form:form>
+			<table id="dataGrid"></table>
+			<div id="dataGridPage"></div>
+		</div>
+	</div>
+</div>
+<% } %>
+<script>
+// 初始化DataGrid对象
+$('#dataGrid').dataGrid({
+	searchForm: $("#searchForm"),
+	columnModel: [
+		// {header:'${text("工序")}', name:'oprno', index:'a.oprno', width:150, align:"center", frozen:true},
+		{header:'${text("故障工序")}', name:'maintainTitle', index:'a.cate_id', width:150, align:"center"},
+		{header:'${text("停台级别")}', name:'level', index:'a.level', width:150, align:"center", formatter: function(val, obj, row, act){
+				return js.getDictLabel(${@DictUtils.getDictListJson('mes_device_fault_level')}, val, '${text("未知")}', true);
+			}},
+		{header:'${text("故障分类")}', name:'cateTitle', index:'a.cate_id', width:150, align:"center"},
+		{header:'${text("故障现象")}', name:'faultPhenomenon', index:'a.fault_phenomenon', width:250, align:"center"},
+		{header:'${text("问题描述")}', name:'problemDescription', index:'a.problem_description', width:250, align:"center"},
+		{header:'${text("根因分析")}', name:'analysis', index:'a.analysis', width:250, align:"center"},
+		{header:'${text("临时措施")}', name:'temporaryMeasures', index:'a.temporary_measures', width:250, align:"center"},
+		{header:'${text("根除措施")}', name:'eradicationMeasures', index:'a.eradication_measures', width:250, align:"center"},
+		{header:'${text("处理人")}', name:'handleBy', index:'a.handle_by', width:150, align:"center"},
+		{header:'${text("开始时间")}', name:'startDate', index:'a.start_date', width:150, align:"center"},
+		{header:'${text("结束时间")}', name:'endDate', index:'a.end_date', width:150, align:"center"},
+		{header:'${text("时长(分钟)")}', name:'duration', index:'a.duration', width:150, align:"center"},
+		{header:'${text("状态")}', name:'state', index:'a.state', width:150, align:"center", formatter: function(val, obj, row, act){
+				return js.getDictLabel(${@DictUtils.getDictListJson('mes_device_fault_state')}, val, '${text("未知")}', true);
+			}},
+		{header:'${text("更新时间")}', name:'updateDate', index:'a.update_date', width:150, align:"center"},
+		{header:'${text("操作")}', name:'actions', width:120, frozen:true, formatter: function(val, obj, row, act){
+			var actions = [];
+			//<% if(hasPermi('mes:mesDeviceFault:edit')){ %>
+				actions.push('<a href="${ctx}/mes/mesDeviceFault/form?id='+row.id+'" class="btnList" title="${text("编辑设备故障记录")}"><i class="fa fa-pencil"></i></a>&nbsp;');
+				actions.push('<a href="${ctx}/mes/mesDeviceFault/delete?id='+row.id+'" class="btnList" title="${text("删除设备故障记录")}" data-confirm="${text("确认要删除该设备故障记录吗?")}"><i class="fa fa-trash-o"></i></a>&nbsp;');
+			//<% } %>
+			return actions.join('');
+		}}
+	],
+	frozenCols: true,
+	// 加载成功后执行事件
+	ajaxSuccess: function(data){
+		
+	}
+});
+</script>
+<script>
+$('#btnExport').click(function(){
+	js.ajaxSubmitForm($('#searchForm'), {
+		url:'${ctx}/mes/mesDeviceFault/exportData',
+		downloadFile:true
+	});
+});
+$('#btnImport').click(function(){
+	js.layer.open({
+		type: 1,
+		area: ['400px'],
+		title: '${text("导入设备故障记录")}',
+		resize: false,
+		scrollbar: true,
+		content: js.template('importTpl'),
+		btn: ['<i class="fa fa-check"></i> ${text("导入")}',
+			'<i class="fa fa-remove"></i> ${text("关闭")}'],
+		btn1: function(index, layero){
+			var form = {
+				inputForm: layero.find('#inputForm'),
+				file: layero.find('#file').val()
+			};
+		    if (form.file == '' || (!js.endWith(form.file, '.xls') && !js.endWith(form.file, '.xlsx'))){
+		    	js.showMessage("${text('文件不正确,请选择后缀为“xls”或“xlsx”的文件。')}", null, 'warning');
+		        return false;
+		    }
+			js.ajaxSubmitForm(form.inputForm, function(data){
+				js.showMessage(data.message);
+				if(data.result == Global.TRUE){
+					js.layer.closeAll();
+				}
+				page();
+			}, "json");
+			return true;
+		}
+	});
+});
+</script>
+<script id="importTpl" type="text/template">//<!--
+<form id="inputForm" action="${ctx}/mes/mesDeviceFault/importData" method="post" enctype="multipart/form-data"
+	class="form-horizontal mt20 mb10" style="overflow:auto;max-height:200px;">
+	<div class="row">
+		<div class="col-xs-12 col-xs-offset-1">
+			<input type="file" id="file" name="file" class="form-file"/>
+			<div class="mt10 pt5" style="color:red">
+				${text('提示:仅允许导入“xls”或“xlsx”格式文件!')}
+			</div>
+			<div class="mt10 pt5">
+				<a href="${ctx}/mes/mesDeviceFault/importTemplate" class="btn btn-default btn-xs"><i class="fa fa-file-excel-o"></i> ${text('下载模板')}</a>
+			</div>
+		</div>
+	</div>
+</form>
+//--></script>

+ 64 - 0
src/main/resources/views/modules/mes/mesDeviceFaultMaintainForm.html

@@ -0,0 +1,64 @@
+<% layout('/layouts/default.html', {title: '设备故障工序管理', libs: ['validate']}){ %>
+<div class="main-content">
+	<div class="box box-main">
+		<div class="box-header with-border">
+			<div class="box-title">
+				<i class="fa icon-note"></i> ${text(mesDeviceFaultMaintain.isNewRecord ? '新增设备工序维护' : '编辑设备工序维护')}
+			</div>
+			<div class="box-tools pull-right">
+				<button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>
+			</div>
+		</div>
+		<#form:form id="inputForm" model="${mesDeviceFaultMaintain}" action="${ctx}/mes/mesDeviceFaultMaintain/save" method="post" class="form-horizontal">
+			<div class="box-body">
+				<div class="form-unit">${text('基本信息')}</div>
+				<#form:hidden path="id"/>
+				<div class="row">
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required hide">*</span> ${text('名称')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:input path="title" maxlength="255" class="form-control"/>
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required hide">*</span> ${text('备注')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:input path="remark" maxlength="255" class="form-control"/>
+							</div>
+						</div>
+					</div>
+				</div>
+			</div>
+			<div class="box-footer">
+				<div class="row">
+					<div class="col-sm-offset-2 col-sm-10">
+						<% if (hasPermi('mes:mesDeviceFaultMaintain:edit')){ %>
+							<button type="submit" class="btn btn-sm btn-primary" id="btnSubmit"><i class="fa fa-check"></i> ${text('保 存')}</button>&nbsp;
+						<% } %>
+						<button type="button" class="btn btn-sm btn-default" id="btnCancel" onclick="js.closeCurrentTabPage()"><i class="fa fa-reply-all"></i> ${text('关 闭')}</button>
+					</div>
+				</div>
+			</div>
+		</#form:form>
+	</div>
+</div>
+<% } %>
+<script>
+$("#inputForm").validate({
+	submitHandler: function(form){
+		js.ajaxSubmitForm($(form), function(data){
+			js.showMessage(data.message);
+			if(data.result == Global.TRUE){
+				js.closeCurrentTabPage(function(contentWindow){
+					contentWindow.page();
+				});
+			}
+		}, "json");
+    }
+});
+</script>

+ 160 - 0
src/main/resources/views/modules/mes/mesDeviceFaultMaintainList.html

@@ -0,0 +1,160 @@
+<% layout('/layouts/default.html', {title: '设备故障工序管理', libs: ['dataGrid']}){ %>
+<div class="main-content">
+	<div class="box box-main">
+		<div class="box-header">
+			<div class="box-title">
+				<i class="fa icon-notebook"></i> ${text('设备故障工序管理')}
+			</div>
+			<div class="box-tools pull-right">
+				<a href="#" class="btn btn-default" id="btnSearch" title="${text('查询')}"><i class="fa fa-filter"></i> ${text('查询')}</a>
+<!--				<a href="#" class="btn btn-default" id="btnExport"><i class="glyphicon glyphicon-export"></i> 导出</a>-->
+				<% if(hasPermi('mes:mesDeviceFaultMaintain:edit')){ %>
+<!--						<a href="#" class="btn btn-default" id="btnImport"><i class="glyphicon glyphicon-import"></i> 导入</a>-->
+					<a href="${ctx}/mes/mesDeviceFaultMaintain/form" class="btn btn-default btnTool" title="${text('新增设备故障维护')}"><i class="fa fa-plus"></i> ${text('新增')}</a>
+				<% } %>
+				<a href="#" class="btn btn-default" id="btnSetting" title="${text('设置')}"><i class="fa fa-navicon"></i></a>
+			</div>
+		</div>
+		<div class="box-body">
+			<#form:form id="searchForm" model="${mesDeviceFaultMaintain}" action="${ctx}/mes/mesDeviceFaultMaintain/listData" method="post" class="form-inline hide"
+					data-page-no="${parameter.pageNo}" data-page-size="${parameter.pageSize}" data-order-by="${parameter.orderBy}">
+				<div class="form-group">
+					<label class="control-label">${text('名称')}:</label>
+					<div class="control-inline">
+						<#form:input path="title" maxlength="255" class="form-control width-120"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('备注')}:</label>
+					<div class="control-inline">
+						<#form:input path="remark" maxlength="255" class="form-control width-120"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('更新时间')}:</label>
+					<div class="control-inline">
+						<#form:input path="updateDate_gte" readonly="true" maxlength="20" class="form-control laydate width-datetime"
+							dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm" data-done="updateDate_lte.click()"/>
+						&nbsp;-&nbsp;
+						<#form:input path="updateDate_lte" readonly="true" maxlength="20" class="form-control laydate width-datetime"
+							dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm"/>
+					</div>
+				</div>
+	<!--				<div class="form-group">-->
+	<!--					<label class="control-label">${text('create_by')}:</label>-->
+	<!--					<div class="control-inline">-->
+	<!--						<#form:input path="createBy" maxlength="64" class="form-control width-120"/>-->
+	<!--					</div>-->
+	<!--				</div>-->
+	<!--				<div class="form-group">-->
+	<!--					<label class="control-label">${text('update_by')}:</label>-->
+	<!--					<div class="control-inline">-->
+	<!--						<#form:input path="updateBy" maxlength="64" class="form-control width-120"/>-->
+	<!--					</div>-->
+	<!--				</div>-->
+				<div class="form-group">
+					<label class="control-label">${text('状态')}:</label>
+					<div class="control-inline width-120">
+						<#form:select path="status" dictType="sys_search_status" blankOption="true" class="form-control isQuick"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<button type="submit" class="btn btn-primary btn-sm">${text('查询')}</button>
+					<button type="reset" class="btn btn-default btn-sm">${text('重置')}</button>
+				</div>
+			</#form:form>
+			<table id="dataGrid"></table>
+			<div id="dataGridPage"></div>
+		</div>
+	</div>
+</div>
+<% } %>
+<script>
+// 初始化DataGrid对象
+$('#dataGrid').dataGrid({
+	searchForm: $("#searchForm"),
+	columnModel: [
+		{header:'${text("名称")}', name:'title', index:'a.title', width:150, align:"center", frozen:true, formatter: function(val, obj, row, act){
+			return '<a href="${ctx}/mes/mesDeviceFaultMaintain/form?id='+row.id+'" class="btnList" data-title="${text("编辑设备故障维护")}">'+(val||row.id)+'</a>';
+		}},
+		{header:'${text("备注")}', name:'remark', index:'a.remark', width:150, align:"center"},
+		// {header:'${text("创建时间")}', name:'createDate', index:'a.create_date', width:150, align:"center"},
+		{header:'${text("更新时间")}', name:'updateDate', index:'a.update_date', width:150, align:"center"},
+		// {header:'${text("create_by")}', name:'createBy', index:'a.create_by', width:150, align:"left"},
+		// {header:'${text("update_by")}', name:'updateBy', index:'a.update_by', width:150, align:"left"},
+		{header:'${text("状态")}', name:'status', index:'a.status', width:150, align:"center", formatter: function(val, obj, row, act){
+			return js.getDictLabel(${@DictUtils.getDictListJson('sys_search_status')}, val, '${text("未知")}', true);
+		}},
+		{header:'${text("操作")}', name:'actions', width:120, formatter: function(val, obj, row, act){
+			var actions = [];
+			//<% if(hasPermi('mes:mesDeviceFaultMaintain:edit')){ %>
+				actions.push('<a href="${ctx}/mes/mesDeviceFaultMaintain/form?id='+row.id+'" class="btnList" title="${text("编辑设备故障维护")}"><i class="fa fa-pencil"></i></a>&nbsp;');
+				if (row.status == Global.STATUS_NORMAL){
+					actions.push('<a href="${ctx}/mes/mesDeviceFaultMaintain/disable?id='+row.id+'" class="btnList" title="${text("停用设备故障维护")}" data-confirm="${text("确认要停用该设备故障维护吗?")}"><i class="glyphicon glyphicon-ban-circle"></i></a>&nbsp;');
+				} else if (row.status == Global.STATUS_DISABLE){
+					actions.push('<a href="${ctx}/mes/mesDeviceFaultMaintain/enable?id='+row.id+'" class="btnList" title="${text("启用设备故障维护")}" data-confirm="${text("确认要启用该设备故障维护吗?")}"><i class="glyphicon glyphicon-ok-circle"></i></a>&nbsp;');
+				}
+				actions.push('<a href="${ctx}/mes/mesDeviceFaultMaintain/delete?id='+row.id+'" class="btnList" title="${text("删除设备故障维护")}" data-confirm="${text("确认要删除该设备故障维护吗?")}"><i class="fa fa-trash-o"></i></a>&nbsp;');
+			//<% } %>
+			return actions.join('');
+		}}
+	],
+	// 加载成功后执行事件
+	ajaxSuccess: function(data){
+		
+	}
+});
+</script><script>
+$('#btnExport').click(function(){
+	js.ajaxSubmitForm($('#searchForm'), {
+		url:'${ctx}/mes/mesDeviceFaultMaintain/exportData',
+		downloadFile:true
+	});
+});
+$('#btnImport').click(function(){
+	js.layer.open({
+		type: 1,
+		area: ['400px'],
+		title: '${text("导入设备故障维护")}',
+		resize: false,
+		scrollbar: true,
+		content: js.template('importTpl'),
+		btn: ['<i class="fa fa-check"></i> ${text("导入")}',
+			'<i class="fa fa-remove"></i> ${text("关闭")}'],
+		btn1: function(index, layero){
+			var form = {
+				inputForm: layero.find('#inputForm'),
+				file: layero.find('#file').val()
+			};
+		    if (form.file == '' || (!js.endWith(form.file, '.xls') && !js.endWith(form.file, '.xlsx'))){
+		    	js.showMessage("${text('文件不正确,请选择后缀为“xls”或“xlsx”的文件。')}", null, 'warning');
+		        return false;
+		    }
+			js.ajaxSubmitForm(form.inputForm, function(data){
+				js.showMessage(data.message);
+				if(data.result == Global.TRUE){
+					js.layer.closeAll();
+				}
+				page();
+			}, "json");
+			return true;
+		}
+	});
+});
+</script>
+<script id="importTpl" type="text/template">//<!--
+<form id="inputForm" action="${ctx}/mes/mesDeviceFaultMaintain/importData" method="post" enctype="multipart/form-data"
+	class="form-horizontal mt20 mb10" style="overflow:auto;max-height:200px;">
+	<div class="row">
+		<div class="col-xs-12 col-xs-offset-1">
+			<input type="file" id="file" name="file" class="form-file"/>
+			<div class="mt10 pt5" style="color:red">
+				${text('提示:仅允许导入“xls”或“xlsx”格式文件!')}
+			</div>
+			<div class="mt10 pt5">
+				<a href="${ctx}/mes/mesDeviceFaultMaintain/importTemplate" class="btn btn-default btn-xs"><i class="fa fa-file-excel-o"></i> ${text('下载模板')}</a>
+			</div>
+		</div>
+	</div>
+</form>
+//--></script>

+ 440 - 0
src/main/resources/views/modules/mes/mesDeviceFaultTj.html

@@ -0,0 +1,440 @@
+<% layout('/layouts/default.html', {title: '设备故障记录管理', libs: ['dataGrid']}){ %>
+<div class="main-content">
+	<div class="box box-main" style="margin-bottom: 10px;">
+		<div class="box-header">
+			<div class="box-title">
+				<i class="fa icon-notebook"></i> ${text('设备故障类型占比')}
+			</div>
+			<div class="box-tools pull-right"></div>
+		</div>
+		<div class="box-body">
+			<#form:form id="inputForm" model="${mesDeviceFault}" class="form-inline" >
+			<div class="form-group">
+				<label class="control-label">${text('故障工序')}:</label>
+				<div class="control-inline width-120">
+					<#form:select  path="maintainId"  blankOption="true" items="${mesDeviceFaultMaintain}" itemLabel="title" itemValue="id" class="form-control" />
+				</div>
+			</div>
+			<div class="form-group">
+				<label class="control-label">${text('停台级别')}:</label>
+				<div class="control-inline width-120">
+					<#form:select path="level" dictType="mes_device_fault_level" blankOption="true" class="form-control"/>
+				</div>
+			</div>
+				<div class="form-group">
+					<label class="control-label">${text('开始时间')}:</label>
+					<div class="control-inline">
+						<#form:input path="startDate_gte" readonly="true" maxlength="20" class="form-control laydate width-datetime"
+							dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm" data-done="startDate_lte.click()"/>
+						&nbsp;-&nbsp;
+						<#form:input path="startDate_lte" readonly="true" maxlength="20" class="form-control laydate width-datetime"
+							dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('结束时间')}:</label>
+					<div class="control-inline">
+						<#form:input path="endDate_gte" readonly="true" maxlength="20" class="form-control laydate width-datetime"
+							dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm" data-done="endDate_lte.click()"/>
+						&nbsp;-&nbsp;
+						<#form:input path="endDate_lte" readonly="true" maxlength="20" class="form-control laydate width-datetime"
+							dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('状态')}:</label>
+					<div class="control-inline width-120">
+						<#form:select path="state" dictType="mes_device_fault_state" blankOption="true" class="form-control"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<button type="button" onclick="getData()" class="btn btn-primary btn-sm">${text('查询')}</button>
+				</div>
+			</#form:form>
+			<div>
+				<div id="echarts1" style="width: 100%;height: 300px;"></div>
+			</div>
+		</div>
+	</div>
+
+<div class="box box-main" style="margin-bottom: 10px;">
+	<div class="box-header">
+		<div class="box-title">
+			<i class="fa icon-notebook"></i> ${text('设备停台级别占比')}
+		</div>
+		<div class="box-tools pull-right"></div>
+	</div>
+	<div class="box-body">
+		<#form:form id="inputForm2" model="${mesDeviceFault}" class="form-inline" >
+		<div class="form-group">
+			<label class="control-label">${text('故障工序')}:</label>
+			<div class="control-inline width-120">
+				<#form:select  path="maintainId"  blankOption="true" items="${mesDeviceFaultMaintain}" itemLabel="title" itemValue="id" class="form-control" />
+			</div>
+		</div>
+		<div class="form-group">
+			<label class="control-label">${text('故障分类')}:</label>
+			<div class="control-inline width-120">
+				<#form:select  path="cateId"  blankOption="true" items="${mesDeviceFaultCate}" itemLabel="title" itemValue="id" class="form-control" />
+			</div>
+		</div>
+		<div class="form-group">
+			<label class="control-label">${text('开始时间')}:</label>
+			<div class="control-inline">
+				<#form:input path="startDate_gte" readonly="true" maxlength="20" class="form-control laydate width-datetime"
+				dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm" data-done="startDate_lte.click()"/>
+				&nbsp;-&nbsp;
+				<#form:input path="startDate_lte" readonly="true" maxlength="20" class="form-control laydate width-datetime"
+				dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm"/>
+			</div>
+		</div>
+		<div class="form-group">
+			<label class="control-label">${text('结束时间')}:</label>
+			<div class="control-inline">
+				<#form:input path="endDate_gte" readonly="true" maxlength="20" class="form-control laydate width-datetime"
+				dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm" data-done="endDate_lte.click()"/>
+				&nbsp;-&nbsp;
+				<#form:input path="endDate_lte" readonly="true" maxlength="20" class="form-control laydate width-datetime"
+				dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm"/>
+			</div>
+		</div>
+		<div class="form-group">
+			<label class="control-label">${text('状态')}:</label>
+			<div class="control-inline width-120">
+				<#form:select path="state" dictType="mes_device_fault_state" blankOption="true" class="form-control"/>
+			</div>
+		</div>
+		<div class="form-group">
+			<button type="button" onclick="getData2()" class="btn btn-primary btn-sm">${text('查询')}</button>
+<!--			<button type="reset"  class="btn btn-default btn-sm">${text('重置')}</button>-->
+		</div>
+		</#form:form>
+		<div>
+			<div id="echarts2" style="width: 100%;height: 300px;"></div>
+		</div>
+	</div>
+</div>
+
+<div class="box box-main" style="margin-bottom: 10px;">
+	<div class="box-header">
+		<div class="box-title">
+			<i class="fa icon-notebook"></i> ${text('近30天设备故障数统计')}
+		</div>
+		<div class="box-tools pull-right"></div>
+	</div>
+	<div class="box-body">
+		<#form:form id="inputForm3" model="${mesDeviceFault}" class="form-inline" >
+		<div class="form-group">
+			<label class="control-label">${text('故障工序')}:</label>
+			<div class="control-inline width-120">
+				<#form:select  path="maintainId"  blankOption="true" items="${mesDeviceFaultMaintain}" itemLabel="title" itemValue="id" class="form-control" />
+			</div>
+		</div>
+		<div class="form-group">
+			<label class="control-label">${text('停台级别')}:</label>
+			<div class="control-inline width-120">
+				<#form:select path="level" dictType="mes_device_fault_level" blankOption="true" class="form-control"/>
+			</div>
+		</div>
+		<div class="form-group">
+			<label class="control-label">${text('故障分类')}:</label>
+			<div class="control-inline width-120">
+				<#form:select  path="cateId"  blankOption="true" items="${mesDeviceFaultCate}" itemLabel="title" itemValue="id" class="form-control" />
+			</div>
+		</div>
+		<div class="form-group">
+			<label class="control-label">${text('状态')}:</label>
+			<div class="control-inline width-120">
+				<#form:select path="state" dictType="mes_device_fault_state" blankOption="true" class="form-control"/>
+			</div>
+		</div>
+		<div class="form-group">
+			<button type="button" onclick="getData3()" class="btn btn-primary btn-sm">${text('查询')}</button>
+		</div>
+	</#form:form>
+	<div>
+		<div id="echarts3" style="width: 100%;height: 300px;"></div>
+	</div>
+</div>
+</div>
+
+<div class="box box-main" style="margin-bottom: 10px;">
+	<div class="box-header">
+		<div class="box-title">
+			<i class="fa icon-notebook"></i> ${text('近30天设备故障时长统计')}
+		</div>
+		<div class="box-tools pull-right"></div>
+	</div>
+	<div class="box-body">
+		<#form:form id="inputForm4" model="${mesDeviceFault}" class="form-inline" >
+		<div class="form-group">
+			<label class="control-label">${text('故障工序')}:</label>
+			<div class="control-inline width-120">
+				<#form:select  path="maintainId"  blankOption="true" items="${mesDeviceFaultMaintain}" itemLabel="title" itemValue="id" class="form-control" />
+			</div>
+		</div>
+		<div class="form-group">
+			<label class="control-label">${text('停台级别')}:</label>
+			<div class="control-inline width-120">
+				<#form:select path="level" dictType="mes_device_fault_level" blankOption="true" class="form-control"/>
+			</div>
+		</div>
+		<div class="form-group">
+			<label class="control-label">${text('故障分类')}:</label>
+			<div class="control-inline width-120">
+				<#form:select  path="cateId"  blankOption="true" items="${mesDeviceFaultCate}" itemLabel="title" itemValue="id" class="form-control" />
+			</div>
+		</div>
+		<div class="form-group">
+			<label class="control-label">${text('状态')}:</label>
+			<div class="control-inline width-120">
+				<#form:select path="state" dictType="mes_device_fault_state" blankOption="true" class="form-control"/>
+			</div>
+		</div>
+		<div class="form-group">
+			<button type="button" onclick="getData4()" class="btn btn-primary btn-sm">${text('查询')}</button>
+		</div>
+	</#form:form>
+	<div>
+		<div id="echarts4" style="width: 100%;height: 300px;"></div>
+	</div>
+</div>
+</div>
+
+
+
+</div>
+<% } %>
+<script src="${ctxStatic}/echarts/4.2/echarts.min.js"></script>
+<script>
+
+	var chartTheme = $('html').hasClass('skin-dark') > 0 ? 'dark' : 'light';
+
+
+
+	$(function () {
+		getData();
+		getData2();
+		getData3();
+		getData4();
+	});
+
+	function getData(){
+		let url = "/js/a/mes/mesDeviceFault/tjData1";
+		let params = $("#inputForm").serialize();
+
+		$.ajax({
+			type: 'POST',
+			url: url, // 服务器端处理的URL
+			data: params,
+			success: function(ret) {
+				// 成功提交后的回调函数
+				console.log(ret);
+				if(ret.result == "true"){
+					initChart1(ret.data.lists);
+				}
+			},
+			error: function(xhr, status, error) {
+				// 出错时的回调函数
+				console.error(error);
+			}
+		});
+
+		return false;
+	}
+
+	function getData2(){
+		let url = "/js/a/mes/mesDeviceFault/tjData2";
+		let params = $("#inputForm2").serialize();
+
+		$.ajax({
+			type: 'POST',
+			url: url, // 服务器端处理的URL
+			data: params,
+			success: function(ret) {
+				// 成功提交后的回调函数
+				console.log(ret);
+				if(ret.result == "true"){
+					initChart2(ret.data.lists);
+				}
+			},
+			error: function(xhr, status, error) {
+				// 出错时的回调函数
+				console.error(error);
+			}
+		});
+
+		return false;
+	}
+
+	function getData3(){
+		let url = "/js/a/mes/mesDeviceFault/tjData3";
+		let params = $("#inputForm3").serialize();
+
+		$.ajax({
+			type: 'POST',
+			url: url, // 服务器端处理的URL
+			data: params,
+			success: function(ret) {
+				// 成功提交后的回调函数
+				console.log(ret);
+				if(ret.result == "true"){
+					initChart3(ret.data.days,ret.data.lists);
+				}
+			},
+			error: function(xhr, status, error) {
+				// 出错时的回调函数
+				console.error(error);
+			}
+		});
+
+		return false;
+	}
+
+	function getData4(){
+		let url = "/js/a/mes/mesDeviceFault/tjData4";
+		let params = $("#inputForm4").serialize();
+
+		$.ajax({
+			type: 'POST',
+			url: url, // 服务器端处理的URL
+			data: params,
+			success: function(ret) {
+				// 成功提交后的回调函数
+				console.log(ret);
+				if(ret.result == "true"){
+					initChart4(ret.data.days,ret.data.lists);
+				}
+			},
+			error: function(xhr, status, error) {
+				// 出错时的回调函数
+				console.error(error);
+			}
+		});
+
+		return false;
+	}
+
+
+
+	function initChart1(lists){
+		myChart2 = echarts.init(document.getElementById('echarts1'), chartTheme);
+		myChart2.setOption({
+			tooltip: {
+				trigger: 'item',
+				formatter: '{a} <br/>{b} : {c} ({d}%)'
+			},
+			legend: {
+				type: 'scroll',
+				orient: 'vertical',
+				right: 10,
+				top: 20,
+				bottom: 20,
+			},
+			series: [
+				{
+					name:'气缸报警',
+					type:'pie',
+					roseType : 'radius',
+					data: lists,
+					// data:[
+					// 	// {value:12, name:'气缸报警'},
+					// 	// {value:23, name:'配件更换'},
+					// 	// {value:21, name:'易损件更换'},
+					// 	// {value:34, name:'易损件更换2'},
+					// 	// {value:44, name:'易损件更换3'},
+					// 	// {value:22, name:'易损件更换4'},
+					// 	// {value:12, name:'易损件更换5'},
+					// 	// {value:123, name:'易损件更换6'},
+					// 	// {value:22, name:'易损件更换7'},
+					// 	// {value:22, name:'易损件更换8'},
+					// 	// {value:33, name:'易损件更换9'},
+					// 	// {value:12, name:'易损件更换10'},
+					// 	// {value:44, name:'易损件更换11'},
+					// 	// {value:23, name:'易损件更换12'},
+					// 	// {value:55, name:'易损件更换123'},
+					// ]
+				}
+			]
+		});
+	}
+	function initChart2(lists){
+		myChart2 = echarts.init(document.getElementById('echarts2'), chartTheme);
+		myChart2.setOption({
+			tooltip: {
+				trigger: 'item',
+				formatter: '{a} <br/>{b} : {c} ({d}%)'
+			},
+			legend: {
+				type: 'scroll',
+				orient: 'vertical',
+				right: 10,
+				top: 20,
+				bottom: 20,
+			},
+			series: [
+				{
+					name:'气缸报警',
+					type:'pie',
+					// roseType : 'radius',
+					data: lists,
+					// data:[
+					// 	{value:12, name:'A'},
+					// 	{value:23, name:'B'},
+					// 	{value:21, name:'C'},
+					// 	{value:34, name:'D'},
+					// ]
+				}
+			]
+		});
+	}
+
+	function initChart3(days,vals){
+		myChart2 = echarts.init(document.getElementById('echarts3'), chartTheme);
+		myChart2.setOption({
+			xAxis: {
+				type: 'category',
+				data: days
+			},
+			yAxis: {
+				type: 'value'
+			},
+			series: [{
+				data: vals,
+				type: 'bar',
+				showBackground: true,
+				backgroundStyle: {
+					color: 'rgba(220, 220, 220, 0.8)'
+				},
+				label:{
+					show:true
+				}
+			}]
+		});
+	}
+	function initChart4(days,vals){
+		myChart2 = echarts.init(document.getElementById('echarts4'), chartTheme);
+		myChart2.setOption({
+			xAxis: {
+				type: 'category',
+				data: days
+			},
+			yAxis: {
+				type: 'value'
+			},
+			series: [{
+				data: vals,
+				type: 'bar',
+				showBackground: true,
+				backgroundStyle: {
+					color: 'rgba(220, 220, 220, 0.8)'
+				},
+				label:{
+					show:true
+				}
+			}]
+		});
+	}
+
+
+</script>

+ 342 - 0
src/main/resources/views/modules/mes/mesDeviceFaultTj2.html

@@ -0,0 +1,342 @@
+<% layout('/layouts/default.html', {title: '设备故障记录管理', libs: ['dataGrid']}){ %>
+<div class="main-content">
+
+
+
+<div class="box box-main" style="margin-bottom: 10px;">
+    <div class="box-header">
+        <div class="box-title">
+            <i class="fa icon-notebook"></i> ${text('mttr统计和mtbf统计')}
+        </div>
+        <div class="box-tools pull-right"></div>
+    </div>
+    <div class="box-body">
+        <#form:form id="inputForm6" model="${mesDeviceFault}" class="form-inline" >
+        <div class="form-group">
+            <label class="control-label">${text('时间区间')}:</label>
+            <div class="control-inline">
+                <#form:input path="startDate" readonly="true"  maxlength="20" class="form-control laydate width-datetime"
+                dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH" data-done="startDate_lte.click()"/>
+                &nbsp;-&nbsp;
+                <#form:input path="endDate" readonly="true"  maxlength="20" class="form-control laydate width-datetime"
+                dataFormat="datetime"  data-type="datetime" data-format="yyyy-MM-dd HH"/>
+            </div>
+        </div>
+        <div class="form-group">
+        <label class="control-label">${text('故障工序')}:</label>
+        <div class="control-inline width-120">
+            <#form:select  path="maintainId"  blankOption="true" items="${mesDeviceFaultMaintain}" itemLabel="title" itemValue="id" class="form-control" />
+        </div>
+    </div>
+        <div class="form-group">
+            <button type="button" onclick="getData6()" class="btn btn-primary btn-sm">${text('查询')}</button>
+        </div>
+    </#form:form>
+    <div>
+        <div id="echarts6" style="width: 100%;height: 300px;"></div>
+    </div>
+</div>
+    <div class="box box-main">
+        <div class="box-header">
+            <div class="box-title">
+                <i class="fa icon-notebook"></i> ${text('设备故障记录管理')}
+            </div>
+            <div class="box-tools pull-right">
+
+            </div>
+        </div>
+        <div class="box-body">
+            <#form:form id="searchForm" model="${mesDeviceFault}" action="${ctx}/mes/mesDeviceFault/listData" method="post" class="form-inline hide"
+            data-page-no="${parameter.pageNo}" data-page-size="${parameter.pageSize}" data-order-by="${parameter.orderBy}">
+            <div class="form-group">
+                <label class="control-label">${text('故障工序')}:</label>
+                <div class="control-inline width-120">
+                    <#form:select  path="maintainId"  blankOption="true" items="${mesDeviceFaultMaintain}" itemLabel="title" itemValue="id" class="form-control" />
+                </div>
+            </div>
+            <div class="form-group">
+                <label class="control-label">${text('停台级别')}:</label>
+                <div class="control-inline width-120">
+                    <#form:select path="level" dictType="mes_device_fault_level" blankOption="true" class="form-control"/>
+                </div>
+            </div>
+            <div class="form-group">
+                <label class="control-label">${text('故障分类')}:</label>
+                <div class="control-inline width-120">
+                    <#form:select  path="cateId"  blankOption="true" items="${mesDeviceFaultCate}" itemLabel="title" itemValue="id" class="form-control" />
+                </div>
+            </div>
+
+            <div class="form-group">
+                <label class="control-label">${text('故障现象')}:</label>
+                <div class="control-inline">
+                    <#form:input path="faultPhenomenon" maxlength="255" class="form-control width-120"/>
+                </div>
+            </div>
+            <div class="form-group">
+                <label class="control-label">${text('问题描述')}:</label>
+                <div class="control-inline">
+                    <#form:input path="problemDescription" maxlength="255" class="form-control width-120"/>
+                </div>
+            </div>
+            <div class="form-group">
+                <label class="control-label">${text('根因分析')}:</label>
+                <div class="control-inline">
+                    <#form:input path="analysis" maxlength="255" class="form-control width-120"/>
+                </div>
+            </div>
+            <div class="form-group">
+                <label class="control-label">${text('临时措施')}:</label>
+                <div class="control-inline">
+                    <#form:input path="temporaryMeasures" maxlength="255" class="form-control width-120"/>
+                </div>
+            </div>
+            <div class="form-group">
+                <label class="control-label">${text('根除措施')}:</label>
+                <div class="control-inline">
+                    <#form:input path="eradicationMeasures" maxlength="255" class="form-control width-120"/>
+                </div>
+            </div>
+            <div class="form-group">
+                <label class="control-label">${text('处理人')}:</label>
+                <div class="control-inline">
+                    <#form:input path="handleBy" maxlength="255" class="form-control width-120"/>
+                </div>
+            </div>
+            <div class="form-group">
+                <label class="control-label">${text('开始时间')}:</label>
+                <div class="control-inline">
+                    <#form:input path="startDate_gte" readonly="true" maxlength="20" class="form-control laydate width-datetime"
+                    dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm" data-done="startDate_lte.click()"/>
+                    &nbsp;-&nbsp;
+                    <#form:input path="startDate_lte" readonly="true" maxlength="20" class="form-control laydate width-datetime"
+                    dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm"/>
+                </div>
+            </div>
+            <div class="form-group">
+                <label class="control-label">${text('结束时间')}:</label>
+                <div class="control-inline">
+                    <#form:input path="endDate_gte" readonly="true" maxlength="20" class="form-control laydate width-datetime"
+                    dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm" data-done="endDate_lte.click()"/>
+                    &nbsp;-&nbsp;
+                    <#form:input path="endDate_lte" readonly="true" maxlength="20" class="form-control laydate width-datetime"
+                    dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm"/>
+                </div>
+            </div>
+            <div class="form-group">
+                <label class="control-label">${text('状态')}:</label>
+                <div class="control-inline width-120">
+                    <#form:select path="state" dictType="mes_device_fault_state" blankOption="true" class="form-control"/>
+                </div>
+            </div>
+            <div class="form-group">
+                <button type="submit" class="btn btn-primary btn-sm">${text('查询')}</button>
+                <button type="reset" class="btn btn-default btn-sm">${text('重置')}</button>
+            </div>
+        </#form:form>
+        <table id="dataGrid"></table>
+        <div id="dataGridPage"></div>
+    </div>
+</div>
+
+</div>
+<% } %>
+<script src="${ctxStatic}/echarts/4.2/echarts.min.js"></script>
+<script>
+
+    var chartTheme = $('html').hasClass('skin-dark') > 0 ? 'dark' : 'light';
+
+    // Initialize chart
+    var chartDom = document.getElementById('echarts6');
+    var myChart = echarts.init(chartDom);
+
+    $(function () {
+        setDefaultDateValue();
+        getData6();
+    });
+
+
+    function setDefaultDateValue(){
+        var currentDateTime = new Date();
+        currentDateTime.setHours(currentDateTime.getHours() + 1);
+        var formattedDateTime = currentDateTime.getFullYear() + '-' +
+            ('0' + (currentDateTime.getMonth() + 1)).slice(-2) + '-' +
+            ('0' + currentDateTime.getDate()).slice(-2) + ' ' +
+            ('0' + currentDateTime.getHours()).slice(-2);
+
+        document.getElementById('endDate').value = formattedDateTime;
+
+        // 计算七天前的日期
+        currentDateTime.setDate(currentDateTime.getDate() - 7);
+        var year = currentDateTime.getFullYear();
+        var month = ('0' + (currentDateTime.getMonth() + 1)).slice(-2);
+        var day = ('0' + currentDateTime.getDate()).slice(-2);
+        var hours = ('0' + currentDateTime.getHours()).slice(-2);
+        var formattedDate = year + '-' + month + '-' + day + ' ' + hours;
+
+        // 设置 input 元素的值
+        document.getElementById('startDate').value = formattedDate;
+    }
+    function getData6(){
+
+        let url = "/js/a/mes/mesDeviceFault/tjData6";
+        let params = $("#inputForm6").serialize();
+
+        $.ajax({
+            type: 'POST',
+            url: url, // 服务器端处理的URL
+            data: params,
+            success: function(ret) {
+                // 成功提交后的回调函数
+                console.log(ret);
+                if(ret.result == "true"){
+                    initChart6("mttr/mtbf统计", ret.data.legendData, ret.data.xAxisData, ret.data.seriesData);
+                }else{
+                    js.showMessage(ret.message);
+                }
+            },
+            error: function(xhr, status, error) {
+                // 出错时的回调函数
+                console.error(error);
+            }
+        });
+
+        return false;
+    }
+
+
+    function initChart6(title, legendData, xAxisData, seriesData) {
+        var option = {
+            title: {
+                text: title
+            },
+            tooltip: {
+                trigger: 'axis'
+            },
+            legend: {
+                data: legendData
+            },
+            grid: {
+                left: '3%',
+                right: '4%',
+                bottom: '3%',
+                containLabel: true
+            },
+            toolbox: {
+                feature: {
+                    saveAsImage: {}
+                }
+            },
+            xAxis: {
+                type: 'category',
+                boundaryGap: false,
+                data: xAxisData
+            },
+            yAxis: {
+                type: 'value'
+            },
+            series: seriesData.map(series => ({
+                name: series.name,
+                type: 'line',
+                stack: 'Total',
+                data: series.data
+            }))
+        };
+
+        // Set chart option
+        myChart.setOption(option);
+    }
+</script>
+<script>
+    // 初始化DataGrid对象
+    $('#dataGrid').dataGrid({
+        searchForm: $("#searchForm"),
+        columnModel: [
+            // {header:'${text("工序")}', name:'oprno', index:'a.oprno', width:150, align:"center", frozen:true},
+            {header:'${text("故障工序")}', name:'maintainTitle', index:'a.cate_id', width:150, align:"center"},
+            {header:'${text("停台级别")}', name:'level', index:'a.level', width:150, align:"center", formatter: function(val, obj, row, act){
+                    return js.getDictLabel(${@DictUtils.getDictListJson('mes_device_fault_level')}, val, '${text("未知")}', true);
+                }},
+            {header:'${text("故障分类")}', name:'cateTitle', index:'a.cate_id', width:150, align:"center"},
+            {header:'${text("故障现象")}', name:'faultPhenomenon', index:'a.fault_phenomenon', width:250, align:"center"},
+            {header:'${text("问题描述")}', name:'problemDescription', index:'a.problem_description', width:250, align:"center"},
+            {header:'${text("根因分析")}', name:'analysis', index:'a.analysis', width:250, align:"center"},
+            {header:'${text("临时措施")}', name:'temporaryMeasures', index:'a.temporary_measures', width:250, align:"center"},
+            {header:'${text("根除措施")}', name:'eradicationMeasures', index:'a.eradication_measures', width:250, align:"center"},
+            {header:'${text("处理人")}', name:'handleBy', index:'a.handle_by', width:150, align:"center"},
+            {header:'${text("开始时间")}', name:'startDate', index:'a.start_date', width:150, align:"center"},
+            {header:'${text("结束时间")}', name:'endDate', index:'a.end_date', width:150, align:"center"},
+            {header:'${text("时长(分钟)")}', name:'duration', index:'a.duration', width:150, align:"center"},
+            {header:'${text("状态")}', name:'state', index:'a.state', width:150, align:"center", formatter: function(val, obj, row, act){
+                    return js.getDictLabel(${@DictUtils.getDictListJson('mes_device_fault_state')}, val, '${text("未知")}', true);
+                }},
+            {header:'${text("更新时间")}', name:'updateDate', index:'a.update_date', width:150, align:"center"},
+            {header:'${text("操作")}', name:'actions', width:120, frozen:true, formatter: function(val, obj, row, act){
+                    var actions = [];
+                    //<% if(hasPermi('mes:mesDeviceFault:edit')){ %>
+                    actions.push('<a href="${ctx}/mes/mesDeviceFault/form?id='+row.id+'" class="btnList" title="${text("编辑设备故障记录")}"><i class="fa fa-pencil"></i></a>&nbsp;');
+                    actions.push('<a href="${ctx}/mes/mesDeviceFault/delete?id='+row.id+'" class="btnList" title="${text("删除设备故障记录")}" data-confirm="${text("确认要删除该设备故障记录吗?")}"><i class="fa fa-trash-o"></i></a>&nbsp;');
+                    //<% } %>
+                    return actions.join('');
+                }}
+        ],
+        frozenCols: true,
+        // 加载成功后执行事件
+        ajaxSuccess: function(data){
+            getData6();
+        }
+    });
+</script>
+<script>
+    $('#btnExport').click(function(){
+        js.ajaxSubmitForm($('#searchForm'), {
+            url:'${ctx}/mes/mesDeviceFault/exportData',
+            downloadFile:true
+        });
+    });
+    $('#btnImport').click(function(){
+        js.layer.open({
+            type: 1,
+            area: ['400px'],
+            title: '${text("导入设备故障记录")}',
+            resize: false,
+            scrollbar: true,
+            content: js.template('importTpl'),
+            btn: ['<i class="fa fa-check"></i> ${text("导入")}',
+                '<i class="fa fa-remove"></i> ${text("关闭")}'],
+            btn1: function(index, layero){
+                var form = {
+                    inputForm: layero.find('#inputForm'),
+                    file: layero.find('#file').val()
+                };
+                if (form.file == '' || (!js.endWith(form.file, '.xls') && !js.endWith(form.file, '.xlsx'))){
+                    js.showMessage("${text('文件不正确,请选择后缀为“xls”或“xlsx”的文件。')}", null, 'warning');
+                    return false;
+                }
+                js.ajaxSubmitForm(form.inputForm, function(data){
+                    js.showMessage(data.message);
+                    if(data.result == Global.TRUE){
+                        js.layer.closeAll();
+                    }
+                    page();
+                }, "json");
+                return true;
+            }
+        });
+    });
+</script><script id="importTpl" type="text/template">//<!--
+<form id="inputForm" action="${ctx}/mes/mesDeviceFault/importData" method="post" enctype="multipart/form-data"
+	class="form-horizontal mt20 mb10" style="overflow:auto;max-height:200px;">
+	<div class="row">
+		<div class="col-xs-12 col-xs-offset-1">
+			<input type="file" id="file" name="file" class="form-file"/>
+			<div class="mt10 pt5" style="color:red">
+				${text('提示:仅允许导入“xls”或“xlsx”格式文件!')}
+			</div>
+			<div class="mt10 pt5">
+				<a href="${ctx}/mes/mesDeviceFault/importTemplate" class="btn btn-default btn-xs"><i class="fa fa-file-excel-o"></i> ${text('下载模板')}</a>
+			</div>
+		</div>
+	</div>
+</form>
+//--></script>

+ 4 - 1
src/main/resources/views/modules/mes/mesDeviceFormList.html

@@ -54,7 +54,10 @@ $('#dataGrid').dataGrid({
 			return '<a href="${ctx}/mes/mesDeviceForm/form?id='+row.id+'" class="btnList" data-title="${text("编辑设备任务内容")}">'+(val||row.id)+'</a>';
 		}},
 		{header:'${text("设备")}', name:'deviceId', index:'a.device_id', width:150, align:"left", frozen:true, formatter: function(val, obj, row, act){
-				return row.device.treeName;
+				if (row.device && row.device.treeName) {
+					return row.device.treeName;
+				}
+				return '';
 			}},
 		{header:'${text("状态")}', name:'status', index:'a.status', width:150, align:"center", formatter: function(val, obj, row, act){
 			return js.getDictLabel(${@DictUtils.getDictListJson('sys_search_status')}, val, '${text("未知")}', true);

+ 55 - 0
src/main/resources/views/modules/mes/mesDeviceOeeCateForm.html

@@ -0,0 +1,55 @@
+<% layout('/layouts/default.html', {title: 'OEE工序管理', libs: ['validate']}){ %>
+<div class="main-content">
+	<div class="box box-main">
+		<div class="box-header with-border">
+			<div class="box-title">
+				<i class="fa icon-note"></i> ${text(mesDeviceOeeCate.isNewRecord ? '新增OEE工序' : '编辑OEE工序')}
+			</div>
+			<div class="box-tools pull-right">
+				<button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>
+			</div>
+		</div>
+		<#form:form id="inputForm" model="${mesDeviceOeeCate}" action="${ctx}/mes/mesDeviceOeeCate/save" method="post" class="form-horizontal">
+			<div class="box-body">
+				<div class="form-unit">${text('基本信息')}</div>
+				<#form:hidden path="id"/>
+				<div class="row">
+					<div class="col-xs-12">
+						<div class="form-group">
+							<label class="control-label col-sm-2" title="">
+								<span class="required hide">*</span> ${text('名称')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-4">
+								<#form:input path="title" maxlength="255" class="form-control"/>
+							</div>
+						</div>
+					</div>
+				</div>
+			</div>
+			<div class="box-footer">
+				<div class="row">
+					<div class="col-sm-offset-2 col-sm-10">
+						<% if (hasPermi('mes:mesDeviceOeeCate:edit')){ %>
+							<button type="submit" class="btn btn-sm btn-primary" id="btnSubmit"><i class="fa fa-check"></i> ${text('保 存')}</button>&nbsp;
+						<% } %>
+						<button type="button" class="btn btn-sm btn-default" id="btnCancel" onclick="js.closeCurrentTabPage()"><i class="fa fa-reply-all"></i> ${text('关 闭')}</button>
+					</div>
+				</div>
+			</div>
+		</#form:form>
+	</div>
+</div>
+<% } %>
+<script>
+$("#inputForm").validate({
+	submitHandler: function(form){
+		js.ajaxSubmitForm($(form), function(data){
+			js.showMessage(data.message);
+			if(data.result == Global.TRUE){
+				js.closeCurrentTabPage(function(contentWindow){
+					contentWindow.page();
+				});
+			}
+		}, "json");
+    }
+});
+</script>

+ 71 - 0
src/main/resources/views/modules/mes/mesDeviceOeeCateList.html

@@ -0,0 +1,71 @@
+<% layout('/layouts/default.html', {title: 'OEE工序管理', libs: ['dataGrid']}){ %>
+<div class="main-content">
+	<div class="box box-main">
+		<div class="box-header">
+			<div class="box-title">
+				<i class="fa icon-notebook"></i> ${text('OEE工序管理')}
+			</div>
+			<div class="box-tools pull-right">
+				<a href="#" class="btn btn-default" id="btnSearch" title="${text('查询')}"><i class="fa fa-filter"></i> ${text('查询')}</a>
+				<% if(hasPermi('mes:mesDeviceOeeCate:edit')){ %>
+					<a href="${ctx}/mes/mesDeviceOeeCate/form" class="btn btn-default btnTool" title="${text('新增OEE工序')}"><i class="fa fa-plus"></i> ${text('新增')}</a>
+				<% } %>
+				<a href="#" class="btn btn-default" id="btnSetting" title="${text('设置')}"><i class="fa fa-navicon"></i></a>
+			</div>
+		</div>
+		<div class="box-body">
+			<#form:form id="searchForm" model="${mesDeviceOeeCate}" action="${ctx}/mes/mesDeviceOeeCate/listData" method="post" class="form-inline hide"
+					data-page-no="${parameter.pageNo}" data-page-size="${parameter.pageSize}" data-order-by="${parameter.orderBy}">
+				<div class="form-group">
+					<label class="control-label">${text('名称')}:</label>
+					<div class="control-inline">
+						<#form:input path="title" maxlength="255" class="form-control width-120"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('状态')}:</label>
+					<div class="control-inline width-120">
+						<#form:select path="status" dictType="sys_search_status" blankOption="true" class="form-control isQuick"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<button type="submit" class="btn btn-primary btn-sm">${text('查询')}</button>
+					<button type="reset" class="btn btn-default btn-sm">${text('重置')}</button>
+				</div>
+			</#form:form>
+			<table id="dataGrid"></table>
+			<div id="dataGridPage"></div>
+		</div>
+	</div>
+</div>
+<% } %>
+<script>
+// 初始化DataGrid对象
+$('#dataGrid').dataGrid({
+	searchForm: $("#searchForm"),
+	columnModel: [
+		{header:'${text("名称")}', name:'title', index:'a.title', width:150, align:"center", frozen:true},
+		{header:'${text("更新时间")}', name:'updateDate', index:'a.update_date', width:150, align:"center"},
+		{header:'${text("状态")}', name:'status', index:'a.status', width:150, align:"center", formatter: function(val, obj, row, act){
+			return js.getDictLabel(${@DictUtils.getDictListJson('sys_search_status')}, val, '${text("未知")}', true);
+		}},
+		{header:'${text("操作")}', name:'actions', width:120, formatter: function(val, obj, row, act){
+			var actions = [];
+			//<% if(hasPermi('mes:mesDeviceOeeCate:edit')){ %>
+				actions.push('<a href="${ctx}/mes/mesDeviceOeeCate/form?id='+row.id+'" class="btnList" title="${text("编辑OEE工序")}"><i class="fa fa-pencil"></i></a>&nbsp;');
+				if (row.status == Global.STATUS_NORMAL){
+					actions.push('<a href="${ctx}/mes/mesDeviceOeeCate/disable?id='+row.id+'" class="btnList" title="${text("停用OEE工序")}" data-confirm="${text("确认要停用该OEE工序吗?")}"><i class="glyphicon glyphicon-ban-circle"></i></a>&nbsp;');
+				} else if (row.status == Global.STATUS_DISABLE){
+					actions.push('<a href="${ctx}/mes/mesDeviceOeeCate/enable?id='+row.id+'" class="btnList" title="${text("启用OEE工序")}" data-confirm="${text("确认要启用该OEE工序吗?")}"><i class="glyphicon glyphicon-ok-circle"></i></a>&nbsp;');
+				}
+				actions.push('<a href="${ctx}/mes/mesDeviceOeeCate/delete?id='+row.id+'" class="btnList" title="${text("删除OEE工序")}" data-confirm="${text("确认要删除该OEE工序吗?")}"><i class="fa fa-trash-o"></i></a>&nbsp;');
+			//<% } %>
+			return actions.join('');
+		}}
+	],
+	// 加载成功后执行事件
+	ajaxSuccess: function(data){
+		
+	}
+});
+</script>

+ 83 - 0
src/main/resources/views/modules/mes/mesDeviceOeeForm.html

@@ -0,0 +1,83 @@
+<% layout('/layouts/default.html', {title: 'OEE管理', libs: ['validate']}){ %>
+<div class="main-content">
+	<div class="box box-main">
+		<div class="box-header with-border">
+			<div class="box-title">
+				<i class="fa icon-note"></i> ${text(mesDeviceOee.isNewRecord ? '新增OEE产量' : '编辑OEE产量')}
+			</div>
+			<div class="box-tools pull-right">
+				<button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>
+			</div>
+		</div>
+		<#form:form id="inputForm" model="${mesDeviceOee}" action="${ctx}/mes/mesDeviceOee/save" method="post" class="form-horizontal">
+			<div class="box-body">
+				<div class="form-unit">${text('基本信息')}</div>
+				<#form:hidden path="id"/>
+				<div class="row">
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required ">*</span> ${text('阶段')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:select  path="cateId"  blankOption="true" items="${mesDeviceOeeCate}" itemLabel="title" itemValue="id" class="form-control required" />
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required ">*</span> ${text('日期')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:input path="date" readonly="true" maxlength="20" class="form-control laydate required"
+									dataFormat="date" data-type="date" data-format="yyyy-MM-dd"/>
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required hide">*</span> ${text('计划产量')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:input path="planNum" defaultValue="0" maxlength="8" class="form-control digits"/>
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required hide">*</span> ${text('当日产量')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:input path="todayNum" defaultValue="0" maxlength="8" class="form-control digits"/>
+							</div>
+						</div>
+					</div>
+				</div>
+			</div>
+			<div class="box-footer">
+				<div class="row">
+					<div class="col-sm-offset-2 col-sm-10">
+						<% if (hasPermi('mes:mesDeviceOee:edit')){ %>
+							<button type="submit" class="btn btn-sm btn-primary" id="btnSubmit"><i class="fa fa-check"></i> ${text('保 存')}</button>&nbsp;
+						<% } %>
+						<button type="button" class="btn btn-sm btn-default" id="btnCancel" onclick="js.closeCurrentTabPage()"><i class="fa fa-reply-all"></i> ${text('关 闭')}</button>
+					</div>
+				</div>
+			</div>
+		</#form:form>
+	</div>
+</div>
+<% } %>
+<script>
+$("#inputForm").validate({
+	submitHandler: function(form){
+		js.ajaxSubmitForm($(form), function(data){
+			js.showMessage(data.message);
+			if(data.result == Global.TRUE){
+				js.closeCurrentTabPage(function(contentWindow){
+					contentWindow.page();
+				});
+			}
+		}, "json");
+    }
+});
+</script>

+ 123 - 0
src/main/resources/views/modules/mes/mesDeviceOeeList.html

@@ -0,0 +1,123 @@
+<% layout('/layouts/default.html', {title: 'OEE管理', libs: ['dataGrid']}){ %>
+<div class="main-content">
+	<div class="box box-main">
+		<div class="box-header">
+			<div class="box-title">
+				<i class="fa icon-notebook"></i> ${text('OEE产量管理')}
+			</div>
+			<div class="box-tools pull-right">
+				<a href="#" class="btn btn-default" id="btnSearch" title="${text('查询')}"><i class="fa fa-filter"></i> ${text('查询')}</a>
+<!--				<a href="#" class="btn btn-default" id="btnExport"><i class="glyphicon glyphicon-export"></i> 导出</a>-->
+				<% if(hasPermi('mes:mesDeviceOee:edit')){ %>
+<!--						<a href="#" class="btn btn-default" id="btnImport"><i class="glyphicon glyphicon-import"></i> 导入</a>-->
+					<a href="${ctx}/mes/mesDeviceOee/form" class="btn btn-default btnTool" title="${text('新增OEE产量')}"><i class="fa fa-plus"></i> ${text('新增产量')}</a>
+				<% } %>
+				<a href="${ctx}/mes/mesDeviceOee/tj" class="btn btn-default btnTool" title="${text('统计')}"><i class="fa fa-plus"></i> ${text('统计')}</a>
+				<a href="#" class="btn btn-default" id="btnSetting" title="${text('设置')}"><i class="fa fa-navicon"></i></a>
+			</div>
+		</div>
+		<div class="box-body">
+			<#form:form id="searchForm" model="${mesDeviceOee}" action="${ctx}/mes/mesDeviceOee/listData" method="post" class="form-inline hide"
+					data-page-no="${parameter.pageNo}" data-page-size="${parameter.pageSize}" data-order-by="${parameter.orderBy}">
+				<div class="form-group">
+					<label class="control-label">${text('阶段')}:</label>
+					<div class="control-inline width-120">
+						<#form:select  path="cateId"  blankOption="true" items="${mesDeviceOeeCate}" itemLabel="title" itemValue="id" class="form-control" />
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('日期')}:</label>
+					<div class="control-inline">
+						<#form:input path="date" readonly="true" maxlength="20" class="form-control laydate width-date"
+							dataFormat="date" data-type="date" data-format="yyyy-MM-dd"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<button type="submit" class="btn btn-primary btn-sm">${text('查询')}</button>
+					<button type="reset" class="btn btn-default btn-sm">${text('重置')}</button>
+				</div>
+			</#form:form>
+			<table id="dataGrid"></table>
+			<div id="dataGridPage"></div>
+		</div>
+	</div>
+</div>
+<% } %>
+<script>
+// 初始化DataGrid对象
+$('#dataGrid').dataGrid({
+	searchForm: $("#searchForm"),
+	columnModel: [
+		{header:'${text("阶段")}', name:'cateTitle', index:'b.title', width:150, align:"center", frozen:true},
+		{header:'${text("日期")}', name:'date', index:'a.date', width:150, align:"center"},
+		{header:'${text("计划产量")}', name:'planNum', index:'a.plan_num', width:150, align:"center"},
+		{header:'${text("当日产量")}', name:'todayNum', index:'a.today_num', width:150, align:"center"},
+		{header:'${text("更新时间")}', name:'updateDate', index:'a.update_date', width:150, align:"center"},
+		{header:'${text("操作")}', name:'actions', width:120, formatter: function(val, obj, row, act){
+			var actions = [];
+			//<% if(hasPermi('mes:mesDeviceOee:edit')){ %>
+				actions.push('<a href="${ctx}/mes/mesDeviceOee/form?id='+row.id+'" class="btnList" title="${text("编辑OEE")}"><i class="fa fa-pencil"></i></a>&nbsp;');
+				actions.push('<a href="${ctx}/mes/mesDeviceOee/delete?id='+row.id+'" class="btnList" title="${text("删除OEE")}" data-confirm="${text("确认要删除该OEE吗?")}"><i class="fa fa-trash-o"></i></a>&nbsp;');
+			//<% } %>
+			return actions.join('');
+		}}
+	],
+	// 加载成功后执行事件
+	ajaxSuccess: function(data){
+		
+	}
+});
+</script><script>
+$('#btnExport').click(function(){
+	js.ajaxSubmitForm($('#searchForm'), {
+		url:'${ctx}/mes/mesDeviceOee/exportData',
+		downloadFile:true
+	});
+});
+$('#btnImport').click(function(){
+	js.layer.open({
+		type: 1,
+		area: ['400px'],
+		title: '${text("导入OEE")}',
+		resize: false,
+		scrollbar: true,
+		content: js.template('importTpl'),
+		btn: ['<i class="fa fa-check"></i> ${text("导入")}',
+			'<i class="fa fa-remove"></i> ${text("关闭")}'],
+		btn1: function(index, layero){
+			var form = {
+				inputForm: layero.find('#inputForm'),
+				file: layero.find('#file').val()
+			};
+		    if (form.file == '' || (!js.endWith(form.file, '.xls') && !js.endWith(form.file, '.xlsx'))){
+		    	js.showMessage("${text('文件不正确,请选择后缀为“xls”或“xlsx”的文件。')}", null, 'warning');
+		        return false;
+		    }
+			js.ajaxSubmitForm(form.inputForm, function(data){
+				js.showMessage(data.message);
+				if(data.result == Global.TRUE){
+					js.layer.closeAll();
+				}
+				page();
+			}, "json");
+			return true;
+		}
+	});
+});
+</script>
+<script id="importTpl" type="text/template">//<!--
+<form id="inputForm" action="${ctx}/mes/mesDeviceOee/importData" method="post" enctype="multipart/form-data"
+	class="form-horizontal mt20 mb10" style="overflow:auto;max-height:200px;">
+	<div class="row">
+		<div class="col-xs-12 col-xs-offset-1">
+			<input type="file" id="file" name="file" class="form-file"/>
+			<div class="mt10 pt5" style="color:red">
+				${text('提示:仅允许导入“xls”或“xlsx”格式文件!')}
+			</div>
+			<div class="mt10 pt5">
+				<a href="${ctx}/mes/mesDeviceOee/importTemplate" class="btn btn-default btn-xs"><i class="fa fa-file-excel-o"></i> ${text('下载模板')}</a>
+			</div>
+		</div>
+	</div>
+</form>
+//--></script>

+ 97 - 0
src/main/resources/views/modules/mes/mesDeviceOeeTj.html

@@ -0,0 +1,97 @@
+<% layout('/layouts/default.html', {title: 'OEE统计管理', libs: ['dataGrid']}){ %>
+
+<div class="box box-main" style="margin-bottom: 10px;">
+    <div class="box-header">
+        <div class="box-title">
+            <i class="fa icon-notebook"></i> ${text('性能率')}
+        </div>
+        <div class="box-tools pull-right"></div>
+    </div>
+    <div class="box-body">
+        <#form:form id="inputForm5" model="${mesDeviceOee}" class="form-inline" >
+        <div class="form-group">
+            <label class="control-label">${text('日期')}:</label>
+            <div class="control-inline">
+                <#form:input path="sdate" readonly="true" maxlength="20" class="form-control laydate width-datetime"
+                dataFormat="date" data-type="date" data-format="yyyy-MM-dd"/>
+                &nbsp;-&nbsp;
+                <#form:input path="edate" readonly="true" maxlength="20" class="form-control laydate width-datetime"
+                dataFormat="date" data-type="date" data-format="yyyy-MM-dd"/>
+            </div>
+        </div>
+
+        <div class="form-group">
+            <button type="button" onclick="getData5()" class="btn btn-primary btn-sm">${text('查询')}</button>
+        </div>
+    </#form:form>
+    <div>
+        <div id="echarts5" style="width: 100%;height: 300px;"></div>
+    </div>
+</div>
+
+</div>
+<% } %>
+<script src="${ctxStatic}/echarts/4.2/echarts.min.js"></script>
+<script>
+
+    var chartTheme = $('html').hasClass('skin-dark') > 0 ? 'dark' : 'light';
+
+
+    $(function () {
+        getData5();
+    });
+
+
+    function getData5(){
+        let url = "/js/a/mes/mesDeviceOee/tjData5";
+        let params = $("#inputForm5").serialize();
+
+        $.ajax({
+            type: 'POST',
+            url: url, // 服务器端处理的URL
+            data: params,
+            success: function(ret) {
+                // 成功提交后的回调函数
+                console.log(ret);
+                if(ret.result == "true"){
+                    initChart5(ret.data.titles,ret.data.oees);
+                }
+            },
+            error: function(xhr, status, error) {
+                // 出错时的回调函数
+                console.error(error);
+            }
+        });
+
+        return false;
+    }
+
+    function initChart5(titles, oees) {
+        myChart2 = echarts.init(document.getElementById('echarts5'), chartTheme);
+        myChart2.setOption({
+            xAxis: {
+                type: 'category',
+                data: titles
+            },
+            yAxis: {
+                type: 'value',
+                axisLabel: {
+                    formatter: '{value}%'
+                }
+            },
+            series: [{
+                data: oees,
+                type: 'bar',
+                showBackground: true,
+                backgroundStyle: {
+                    color: 'rgba(220, 220, 220, 0.8)'
+                },
+                label: {
+                    show: true,
+                    formatter: '{c}%'  // 在标签中添加百分号
+                }
+            }]
+        });
+    }
+
+</script>

+ 56 - 18
src/main/resources/views/modules/mes/mesDevicePreventTaskList.html

@@ -16,7 +16,7 @@
 			</div>
 		</div>
 		<div class="box-body">
-			<#form:form id="searchForm" model="${mesDevicePreventTask}" action="${ctx}/mes/mesDevicePreventTask/listData" method="post" class="form-inline hide"
+			<#form:form id="searchForm" model="${mesDevicePreventTask}" action="${ctx}/mes/mesDevicePreventTask/planListData" method="post" class="form-inline hide"
 					data-page-no="${parameter.pageNo}" data-page-size="${parameter.pageSize}" data-order-by="${parameter.orderBy}">
 				<div class="form-group">
 					<label class="control-label">${text('任务清单')}:</label>
@@ -84,30 +84,68 @@
 $('#dataGrid').dataGrid({
 	searchForm: $("#searchForm"),
 	columnModel: [
-		{header:'${text("任务清单")}', name:'preventTitle', index:'', width:150,sortable:false, align:"center", frozen:true},
-		{header:'${text("执行人员")}', name:'userName', index:'a.user_code', width:150,sortable:false, align:"center"},
-		{header:'${text("实际完成人")}', name:'finishUserName', index:'a.finish_user_code', width:120,sortable:false, align:"center"},
-		{header:'${text("设备")}', name:'deviceName', index:'', width:150,sortable:false, align:"center"},
-		{header:'${text("任务开始时间")}', name:'startDate', index:'a.start_date', width:150, align:"center"},
-		{header:'${text("任务结束时间")}', name:'endDate', index:'a.end_date', width:150, align:"center"},
-		{header:'${text("提交内容")}', name:'content', index:'a.content', width:150,sortable:false, align:"center"},
-		{header:'${text("状态")}', name:'state', index:'a.state', width:150, align:"center", formatter: function(val, obj, row, act){
-			return js.getDictLabel(${@DictUtils.getDictListJson('mes_device_prevent_task_status')}, val, '${text("未知")}', true);
+		{header:'${text("任务清单")}', name:'preventTitle', index:'', width:180, sortable:false, align:"center"},
+		{header:'${text("设备")}', name:'deviceName', index:'', width:160, sortable:false, align:"center"},
+		{header:'${text("执行人员")}', name:'userName', index:'', width:160, sortable:false, align:"center"},
+		{header:'${text("周期")}', name:'cycleDays', index:'', width:80, sortable:false, align:"center", formatter: function(val, obj, row, act){
+			if (val == null || val === '' || val <= 0) {
+				return '—';
+			}
+			return val + '${text("天")}';
+		}},
+		{header:'${text("首期开始")}', name:'startDate', index:'', width:150, sortable:false, align:"center"},
+		{header:'${text("末期结束")}', name:'endDate', index:'', width:150, sortable:false, align:"center"},
+		{header:'${text("完成情况")}', name:'doneCount', index:'', width:110, sortable:false, align:"center", formatter: function(val, obj, row, act){
+			var done = row.doneCount == null ? 0 : row.doneCount;
+			var total = row.taskCount == null ? 0 : row.taskCount;
+			return done + ' / ' + total;
 		}},
-		{header:'${text("创建人")}', name:'createBy', index:'a.create_by', width:120, align:"center"},
-		{header:'${text("创建时间")}', name:'createDate', index:'a.create_date', width:120, align:"center"},
-		{header:'${text("更新人")}', name:'updateBy', index:'a.update_by', width:120, align:"center"},
-		{header:'${text("更新时间")}', name:'updateDate', index:'a.update_date', width:125, align:"center"},
-		{header:'${text("操作")}', name:'actions', width:120, formatter: function(val, obj, row, act){
+		{header:'${text("操作")}', name:'actions', width:80, sortable:false, align:"center", formatter: function(val, obj, row, act){
 			var actions = [];
 			//<% if(hasPermi('mes:mesDevicePreventTask:edit')){ %>
-				actions.push('<a href="${ctx}/mes/mesDevicePreventTask/form?id='+row.id+'" class="btnList" title="${text("编辑预防性维修计划")}"><i class="fa fa-pencil"></i></a>&nbsp;');
-				actions.push('<a href="${ctx}/mes/mesDevicePreventTask/delete?id='+row.id+'" class="btnList" title="${text("删除预防性维修计划")}" data-confirm="${text("确认要删除该预防性维修计划吗?")}"><i class="fa fa-trash-o"></i></a>&nbsp;');
+				actions.push('<a href="${ctx}/mes/mesDevicePreventTask/deleteBatch?batchId='+row.id+'" class="btnList" title="${text("删除该维护计划")}" data-confirm="${text("确认要删除该维护计划及其全部周期任务吗?")}"><i class="fa fa-trash-o"></i></a>&nbsp;');
 			//<% } %>
 			return actions.join('');
 		}}
 	],
-	// 加载成功后执行事件
+	subGrid: true,
+	subGridRowExpanded: function (subgridId, rowId) {
+		var postData = {batchId: rowId, pageSize: 500};
+		$('#searchForm').serializeArray().forEach(function(item){
+			if (item.name !== 'pageNo' && item.name !== 'pageSize' && item.name !== 'orderBy') {
+				postData[item.name] = item.value;
+			}
+		});
+		$('#'+subgridId).html('<table id="'+subgridId+'_subgrid"></table>');
+		$('#'+subgridId+'_subgrid').dataGrid({
+			url: '${ctx}/mes/mesDevicePreventTask/planChildData',
+			postData: postData,
+			autoGridHeight: function(){return 'auto'},
+			autoGridWidth: function(){return $('#'+subgridId).width()},
+			columnModel: [
+				{header:'${text("任务开始时间")}', name:'startDate', width:150, align:"center"},
+				{header:'${text("任务结束时间")}', name:'endDate', width:150, align:"center"},
+				{header:'${text("状态")}', name:'state', width:100, align:"center", formatter: function(val, obj, row, act){
+					return js.getDictLabel(${@DictUtils.getDictListJson('mes_device_prevent_task_status')}, val, '${text("未知")}', true);
+				}},
+				{header:'${text("实际完成人")}', name:'finishUserName', width:120, align:"center"},
+				{header:'${text("提交内容")}', name:'content', width:180, align:"center"},
+				{header:'${text("操作")}', name:'actions', width:120, align:"center", formatter: function(val, obj, row, act){
+					var actions = [];
+					actions.push('<a href="${ctx}/mes/mesDevicePreventTask/info?id='+row.id+'" class="btnList" title="${text("查看详情")}"><i class="fa fa-fw fa-eye"></i></a>&nbsp;');
+					//<% if(hasPermi('mes:mesDevicePreventTask:edit')){ %>
+						actions.push('<a href="${ctx}/mes/mesDevicePreventTask/form?id='+row.id+'" class="btnList" title="${text("编辑预防性维修计划")}"><i class="fa fa-pencil"></i></a>&nbsp;');
+						actions.push('<a href="${ctx}/mes/mesDevicePreventTask/delete?id='+row.id+'" class="btnList" title="${text("删除预防性维修计划")}" data-confirm="${text("确认要删除该预防性维修计划吗?")}"><i class="fa fa-trash-o"></i></a>&nbsp;');
+					//<% } %>
+					return actions.join('');
+				}}
+			],
+			emptyDataHint: true,
+			ajaxSuccess: function(data){
+				$(window).resize();
+			}
+		});
+	},
 	ajaxSuccess: function(data){
 		
 	}

+ 2 - 3
src/main/resources/views/modules/mes/mesDevicePreventTaskMyList.html

@@ -1,9 +1,9 @@
-<% layout('/layouts/default.html', {title: '预防性维修计划管理', libs: ['dataGrid']}){ %>
+<% layout('/layouts/default.html', {title: '预防性维护记录', libs: ['dataGrid']}){ %>
 <div class="main-content">
 	<div class="box box-main">
 		<div class="box-header">
 			<div class="box-title">
-				<i class="fa icon-notebook"></i> ${text('我的维修计划')}
+				<i class="fa icon-notebook"></i> ${text('预防性维护记录')}
 			</div>
 			<div class="box-tools pull-right">
 				<a href="#" class="btn btn-default" id="btnSearch" title="${text('查询')}"><i class="fa fa-filter"></i> ${text('查询')}</a>
@@ -18,7 +18,6 @@
 		<div class="box-body">
 			<#form:form id="searchForm" model="${mesDevicePreventTask}" action="${ctx}/mes/mesDevicePreventTask/listData" method="post" class="form-inline hide"
 					data-page-no="${parameter.pageNo}" data-page-size="${parameter.pageSize}" data-order-by="${parameter.orderBy}">
-				<input type="hidden" name="myTaskOnly" value="true"/>
 				<div class="form-group">
 					<label class="control-label">${text('任务清单')}:</label>
 					<div class="control-inline">

+ 119 - 0
src/main/resources/views/modules/mes/mesDeviceVulnerableDetail.html

@@ -0,0 +1,119 @@
+<% layout('/layouts/default.html', {title: '产线设备易损件清单详情', libs: ['validate','dataGrid','fileupload']}){ %>
+
+<style>
+	table{
+		width: 100%;
+	}
+	th,td{
+		padding: 10px;
+	}
+	.table.table-bordered th {
+		width: 200px;
+	}
+</style>
+<div class="main-content">
+	<div class="box box-main">
+		<div class="box-header with-border">
+			<div class="box-title">
+				<i class="fa icon-note"></i> 产线设备易损件清单
+			</div>
+			<div class="box-tools pull-right">
+				<button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>
+			</div>
+		</div>
+		<#form:form id="inputForm" model="${mesDeviceVulnerable}" action="${ctx}/mes/mesDeviceVulnerable/save" method="post" class="form-horizontal">
+		<div class="box-body">
+			<div class="form-unit">${text('基本信息')}</div>
+			<table class="table table-bordered">
+				
+				<tr>
+					<th class="mpc-header">工位号</th>
+					<td>${mesDeviceVulnerable.oprno}</td>
+				</tr>
+
+				<tr>
+					<th class="mpc-header">物料编号</th>
+					<td>${mesDeviceVulnerable.materialId}</td>
+				</tr>
+
+				<tr>
+					<th class="mpc-header">设备名称</th>
+					<td>${mesDeviceVulnerable.deviceName}</td>
+				</tr>
+
+				<tr>
+					<th class="mpc-header">型号</th>
+					<td>${mesDeviceVulnerable.model}</td>
+				</tr>
+
+				<tr>
+					<th class="mpc-header">品牌</th>
+					<td>${mesDeviceVulnerable.brand}</td>
+				</tr>
+
+				<tr>
+					<th class="mpc-header">最小库存</th>
+					<td>${mesDeviceVulnerable.minInventory}</td>
+				</tr>
+
+				<tr>
+					<th class="mpc-header">最大库存</th>
+					<td>${mesDeviceVulnerable.maxInventory}</td>
+				</tr>
+
+				<tr>
+					<th class="mpc-header">单位</th>
+					<td>${mesDeviceVulnerable.unit}</td>
+				</tr>
+				<tr>
+					<th class="mpc-header">采购周期</th>
+					<td>${mesDeviceVulnerable.purchaseCycle}</td>
+				</tr>
+
+				<tr>
+					<th class="mpc-header">使用周期</th>
+					<td>${mesDeviceVulnerable.useCycle}</td>
+				</tr>
+
+				<tr>
+					<th class="mpc-header">单价</th>
+					<td>${mesDeviceVulnerable.price}</td>
+				</tr>
+				<tr>
+					<th class="mpc-header">图片</th>
+					<td>
+						<#form:fileupload id="uploadImage" bizKey="${mesDeviceVulnerable.id}" bizType="mesDeviceVulnerable_image"
+						uploadType="image" class="" readonly="true" preview="true"/>
+					</td>
+				</tr>
+
+			</table>
+		</div>
+		<div class="box-footer">
+			<div class="row">
+				<div class="col-sm-offset-2 col-sm-10">
+					<button type="button" class="btn btn-sm btn-default" id="btnCancel" onclick="js.closeCurrentTabPage()"><i class="fa fa-reply-all"></i> ${text('关 闭')}</button>
+				</div>
+			</div>
+		</div>
+	</#form:form>
+</div>
+</div>
+<% } %>
+<script>
+
+</script>
+<script>
+	$("#inputForm").validate({
+		submitHandler: function(form){
+			js.ajaxSubmitForm($(form), function(data){
+				js.showMessage(data.message);
+				if(data.result == Global.TRUE){
+					js.closeCurrentTabPage(function(contentWindow){
+						contentWindow.page();
+					});
+				}
+			}, "json");
+		}
+	});
+</script>

+ 167 - 0
src/main/resources/views/modules/mes/mesDeviceVulnerableForm.html

@@ -0,0 +1,167 @@
+<% layout('/layouts/default.html', {title: ' 产线设备易损件清单管理', libs: ['validate','fileupload']}){ %>
+<div class="main-content">
+	<div class="box box-main">
+		<div class="box-header with-border">
+			<div class="box-title">
+				<i class="fa icon-note"></i> ${text(mesDeviceVulnerable.isNewRecord ? '新增产线设备易损件清单' : '编辑产线设备易损件清单')}
+			</div>
+			<div class="box-tools pull-right">
+				<button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>
+			</div>
+		</div>
+		<#form:form id="inputForm" model="${mesDeviceVulnerable}" action="${ctx}/mes/mesDeviceVulnerable/save" method="post" class="form-horizontal">
+			<div class="box-body">
+				<div class="form-unit">${text('基本信息')}</div>
+				<#form:hidden path="id"/>
+				<div class="row">
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required hide">*</span> ${text('工位编号')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:input path="oprno" maxlength="20" class="form-control"/>
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required hide">*</span> ${text('物料编号')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:input path="materialId" maxlength="64" class="form-control"/>
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required hide">*</span> ${text('工位名称')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:input path="oprnoName" maxlength="100" class="form-control"/>
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required hide">*</span> ${text('设备名称')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:input path="deviceName" maxlength="255" class="form-control"/>
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required hide">*</span> ${text('型号')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:input path="model" maxlength="255" class="form-control"/>
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required hide">*</span> ${text('品牌')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:input path="brand" maxlength="100" class="form-control"/>
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required hide">*</span> ${text('最小库存')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:input path="minInventory" maxlength="9" class="form-control digits"/>
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required hide">*</span> ${text('最大库存')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:input path="maxInventory" maxlength="9" class="form-control digits"/>
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required hide">*</span> ${text('单位')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:input path="unit" maxlength="20" class="form-control"/>
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required hide">*</span> ${text('采购周期')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:input path="purchaseCycle" maxlength="64" class="form-control"/>
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required hide">*</span> ${text('使用周期')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:input path="useCycle" maxlength="100" class="form-control"/>
+							</div>
+						</div>
+					</div>
+					<div class="col-xs-6">
+						<div class="form-group">
+							<label class="control-label col-sm-4" title="">
+								<span class="required hide">*</span> ${text('单价')}:<i class="fa icon-question hide"></i></label>
+							<div class="col-sm-8">
+								<#form:input path="price" maxlength="64" class="form-control"/>
+							</div>
+						</div>
+					</div>
+				</div>
+				<div class="row">
+					<div class="col-xs-12">
+						<div class="form-group">
+							<label class="control-label col-sm-2">
+								<span class="required hide">*</span> ${text('图片上传')}:</label>
+							<div class="col-sm-10">
+								<#form:fileupload id="uploadImage" bizKey="${mesDeviceVulnerable.id}" bizType="mesDeviceVulnerable_image"
+								uploadType="image" class="" readonly="false" preview="true"/>
+							</div>
+						</div>
+					</div>
+				</div>
+			</div>
+
+			<div class="box-footer">
+				<div class="row">
+					<div class="col-sm-offset-2 col-sm-10">
+						<% if (hasPermi('mes:mesDeviceVulnerable:edit')){ %>
+							<button type="submit" class="btn btn-sm btn-primary" id="btnSubmit"><i class="fa fa-check"></i> ${text('保 存')}</button>&nbsp;
+						<% } %>
+						<button type="button" class="btn btn-sm btn-default" id="btnCancel" onclick="js.closeCurrentTabPage()"><i class="fa fa-reply-all"></i> ${text('关 闭')}</button>
+					</div>
+				</div>
+			</div>
+		</#form:form>
+	</div>
+</div>
+<% } %>
+<script>
+$("#inputForm").validate({
+	submitHandler: function(form){
+		js.ajaxSubmitForm($(form), function(data){
+			js.showMessage(data.message);
+			if(data.result == Global.TRUE){
+				js.closeCurrentTabPage(function(contentWindow){
+					contentWindow.page();
+				});
+			}
+		}, "json");
+    }
+});
+</script>

+ 191 - 0
src/main/resources/views/modules/mes/mesDeviceVulnerableList.html

@@ -0,0 +1,191 @@
+<% layout('/layouts/default.html', {title: '产线设备易损件清单管理', libs: ['dataGrid']}){ %>
+<div class="main-content">
+	<div class="box box-main">
+		<div class="box-header">
+			<div class="box-title">
+				<i class="fa icon-notebook"></i> ${text('产线设备易损件清单管理')}
+			</div>
+			<div class="box-tools pull-right">
+				<a href="#" class="btn btn-default" id="btnSearch" title="${text('查询')}"><i class="fa fa-filter"></i> ${text('查询')}</a>
+				<a href="#" class="btn btn-default" id="btnExport"><i class="glyphicon glyphicon-export"></i> 导出</a>
+				<% if(hasPermi('mes:mesDeviceVulnerable:edit')){ %>
+						<a href="#" class="btn btn-default" id="btnImport"><i class="glyphicon glyphicon-import"></i> 导入</a>
+					<a href="${ctx}/mes/mesDeviceVulnerable/form" class="btn btn-default btnTool" title="${text('新增产线设备易损件清单')}"><i class="fa fa-plus"></i> ${text('新增')}</a>
+				<% } %>
+				<a href="#" class="btn btn-default" id="btnSetting" title="${text('设置')}"><i class="fa fa-navicon"></i></a>
+			</div>
+		</div>
+		<div class="box-body">
+			<#form:form id="searchForm" model="${mesDeviceVulnerable}" action="${ctx}/mes/mesDeviceVulnerable/listData" method="post" class="form-inline hide"
+					data-page-no="${parameter.pageNo}" data-page-size="${parameter.pageSize}" data-order-by="${parameter.orderBy}">
+				<div class="form-group">
+					<label class="control-label">${text('工位编号')}:</label>
+					<div class="control-inline">
+						<#form:input path="oprno" maxlength="20" class="form-control width-120"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('物料编号')}:</label>
+					<div class="control-inline">
+						<#form:input path="materialId" maxlength="64" class="form-control width-120"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('工位名称')}:</label>
+					<div class="control-inline">
+						<#form:input path="oprnoName" maxlength="100" class="form-control width-120"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('设备名称')}:</label>
+					<div class="control-inline">
+						<#form:input path="deviceName" maxlength="255" class="form-control width-120"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('型号')}:</label>
+					<div class="control-inline">
+						<#form:input path="model" maxlength="255" class="form-control width-120"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('品牌')}:</label>
+					<div class="control-inline">
+						<#form:input path="brand" maxlength="100" class="form-control width-120"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('最小库存')}:</label>
+					<div class="control-inline">
+						<#form:input path="minInventory" maxlength="9" class="form-control width-120"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('最大库存')}:</label>
+					<div class="control-inline">
+						<#form:input path="maxInventory" maxlength="9" class="form-control width-120"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('单位')}:</label>
+					<div class="control-inline">
+						<#form:input path="unit" maxlength="20" class="form-control width-120"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('采购周期')}:</label>
+					<div class="control-inline">
+						<#form:input path="purchaseCycle" maxlength="64" class="form-control width-120"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('使用周期')}:</label>
+					<div class="control-inline">
+						<#form:input path="useCycle" maxlength="100" class="form-control width-120"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<label class="control-label">${text('单价')}:</label>
+					<div class="control-inline">
+						<#form:input path="price" maxlength="64" class="form-control width-120"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<button type="submit" class="btn btn-primary btn-sm">${text('查询')}</button>
+					<button type="reset" class="btn btn-default btn-sm">${text('重置')}</button>
+				</div>
+			</#form:form>
+			<table id="dataGrid"></table>
+			<div id="dataGridPage"></div>
+		</div>
+	</div>
+</div>
+<% } %>
+<script>
+// 初始化DataGrid对象
+$('#dataGrid').dataGrid({
+	searchForm: $("#searchForm"),
+	columnModel: [
+		{header:'${text("工位编号")}', name:'oprno', index:'a.oprno', width:150, align:"center", frozen:true, formatter: function(val, obj, row, act){
+			return '<a href="${ctx}/mes/mesDeviceVulnerable/form?id='+row.id+'" class="btnList" data-title="${text("编辑产线设备易损件清单")}">'+(val||row.id)+'</a>';
+		}},
+		{header:'${text("物料编号")}', name:'materialId', index:'a.material_id', width:150, align:"center"},
+		{header:'${text("工位名称")}', name:'oprnoName', index:'a.oprno_name', width:150, align:"center"},
+		{header:'${text("设备名称")}', name:'deviceName', index:'a.device_name', width:150, align:"center"},
+		{header:'${text("型号")}', name:'model', index:'a.model', width:150, align:"center"},
+		{header:'${text("品牌")}', name:'brand', index:'a.brand', width:150, align:"center"},
+		{header:'${text("最小库存")}', name:'minInventory', index:'a.min_inventory', width:150, align:"center"},
+		{header:'${text("最大库存")}', name:'maxInventory', index:'a.max_inventory', width:150, align:"center"},
+		{header:'${text("单位")}', name:'unit', index:'a.unit', width:150, align:"center"},
+		{header:'${text("采购周期")}', name:'purchaseCycle', index:'a.purchase_cycle', width:150, align:"center"},
+		{header:'${text("使用周期")}', name:'useCycle', index:'a.use_cycle', width:150, align:"center"},
+		{header:'${text("单价")}', name:'price', index:'a.price', width:150, align:"center"},
+		{header:'${text("操作")}', name:'actions', width:120, formatter: function(val, obj, row, act){
+			var actions = [];
+			//<% if(hasPermi('mes:mesDeviceVulnerable:edit')){ %>
+				actions.push('<a href="${ctx}/mes/mesDeviceVulnerable/form?id='+row.id+'" class="btnList" title="${text("编辑产线设备易损件清单")}"><i class="fa fa-pencil"></i></a>&nbsp;');
+				actions.push('<a href="${ctx}/mes/mesDeviceVulnerable/detail?id='+row.id+'" class="btnList" title="${text("详情")}"><i class="fa fa-fw fa-eye"></i></a>&nbsp;');
+				actions.push('<a href="${ctx}/mes/mesDeviceVulnerable/delete?id='+row.id+'" class="btnList" title="${text("删除产线设备易损件清单")}" data-confirm="${text("确认要删除该产线设备易损件清单吗?")}"><i class="fa fa-trash-o"></i></a>&nbsp;');
+			//<% } %>
+			return actions.join('');
+		}}
+	],
+	// 加载成功后执行事件
+	ajaxSuccess: function(data){
+		
+	}
+});
+</script><script>
+$('#btnExport').click(function(){
+	js.ajaxSubmitForm($('#searchForm'), {
+		url:'${ctx}/mes/mesDeviceVulnerable/exportData',
+		downloadFile:true
+	});
+});
+$('#btnImport').click(function(){
+	js.layer.open({
+		type: 1,
+		area: ['400px'],
+		title: '${text("导入产线设备易损件清单")}',
+		resize: false,
+		scrollbar: true,
+		content: js.template('importTpl'),
+		btn: ['<i class="fa fa-check"></i> ${text("导入")}',
+			'<i class="fa fa-remove"></i> ${text("关闭")}'],
+		btn1: function(index, layero){
+			var form = {
+				inputForm: layero.find('#inputForm'),
+				file: layero.find('#file').val()
+			};
+		    if (form.file == '' || (!js.endWith(form.file, '.xls') && !js.endWith(form.file, '.xlsx'))){
+		    	js.showMessage("${text('文件不正确,请选择后缀为“xls”或“xlsx”的文件。')}", null, 'warning');
+		        return false;
+		    }
+			js.ajaxSubmitForm(form.inputForm, function(data){
+				js.showMessage(data.message);
+				if(data.result == Global.TRUE){
+					js.layer.closeAll();
+				}
+				page();
+			}, "json");
+			return true;
+		}
+	});
+});
+</script>
+<script id="importTpl" type="text/template">//<!--
+<form id="inputForm" action="${ctx}/mes/mesDeviceVulnerable/importData" method="post" enctype="multipart/form-data"
+	class="form-horizontal mt20 mb10" style="overflow:auto;max-height:200px;">
+	<div class="row">
+		<div class="col-xs-12 col-xs-offset-1">
+			<input type="file" id="file" name="file" class="form-file"/>
+			<div class="mt10 pt5" style="color:red">
+				${text('提示:仅允许导入“xls”或“xlsx”格式文件!')}
+			</div>
+			<div class="mt10 pt5">
+				<a href="${ctx}/mes/mesDeviceVulnerable/importTemplate" class="btn btn-default btn-xs"><i class="fa fa-file-excel-o"></i> ${text('下载模板')}</a>
+			</div>
+		</div>
+	</div>
+</form>
+//--></script>