From 49fd89cc2811ff574dea83fa306039be28474285 Mon Sep 17 00:00:00 2001 From: lroyia Date: Tue, 22 Oct 2024 10:46:33 +0800 Subject: [PATCH] =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E5=88=9D=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 5 + README.md | 3 + db/devops.pdma.json | 6665 +++++++++++++++++ db/加入网办入口.sql | 5 + pom.xml | 156 + .../youfool/devops/DevOpsApplication.java | 45 + .../base/controller/DictController.java | 72 + .../base/controller/TaskFileController.java | 60 + .../base/controller/TaskHandleController.java | 31 + .../base/controller/TaskListController.java | 33 + .../base/controller/query/BaseListQuery.java | 33 + .../youfool/devops/base/entity/Dict.java | 68 + .../youfool/devops/base/entity/TaskFile.java | 101 + .../devops/base/entity/TaskHandle.java | 139 + .../youfool/devops/base/entity/TaskList.java | 198 + .../devops/base/mapper/DictMapper.java | 18 + .../devops/base/mapper/TaskFileMapper.java | 16 + .../devops/base/mapper/TaskHandleMapper.java | 21 + .../devops/base/mapper/TaskListMapper.java | 16 + .../devops/base/service/IDictService.java | 35 + .../devops/base/service/IMonitorService.java | 14 + .../devops/base/service/ITaskFileService.java | 43 + .../base/service/ITaskHandleService.java | 44 + .../devops/base/service/ITaskListService.java | 33 + .../base/service/impl/DictServiceImpl.java | 90 + .../base/service/impl/MonitorServiceImpl.java | 115 + .../service/impl/TaskFileServiceImpl.java | 171 + .../service/impl/TaskHandleServiceImpl.java | 82 + .../service/impl/TaskListServiceImpl.java | 65 + .../youfool/devops/config/CorsConfig.java | 25 + .../devops/config/DevopsDataSource.java | 70 + .../youfool/devops/config/FilterConfig.java | 39 + .../devops/config/InterceptorConfig.java | 50 + .../devops/config/PropertySourceConfig.java | 20 + .../devops/config/SchedulingXmlConfig.java | 14 + .../youfool/devops/config/SwaggerKnife4j.java | 123 + .../devops/config/YoufoolDataSource.java | 59 + .../devops/dev/MybatisPlusCodeGenerator.java | 14 + .../controller/AssignController.java | 89 + .../controller/dto/AssignHandleQuery.java | 48 + .../controller/dto/TaskAssignVo.java | 172 + .../devops/leaderassign/entity/Assign.java | 245 + .../leaderassign/mapper/AssignMapper.java | 23 + .../leaderassign/service/IAssignService.java | 52 + .../service/impl/AssignServiceImpl.java | 295 + .../org/business/entity/BusinessUser.java | 49 + .../business/service/BusinessUserService.java | 35 + .../service/impl/BusinessUserServiceImpl.java | 175 + .../org/controller/EngineerController.java | 101 + .../devops/org/controller/UserController.java | 171 + .../youfool/devops/org/entity/Engineer.java | 133 + .../org/interceptor/LoginInterceptor.java | 50 + .../devops/org/mapper/EngineerMapper.java | 16 + .../devops/org/service/IEngineerService.java | 43 + .../org/service/impl/EngineerServiceImpl.java | 204 + .../youfool/devops/repair/api/RobotApi.java | 23 + .../repair/controller/LabelController.java | 64 + .../controller/NotificationController.java | 68 + .../repair/controller/RepairController.java | 248 + .../controller/RepairTodoController.java | 98 + .../controller/StatisticController.java | 205 + .../repair/controller/SummaryController.java | 80 + .../controller/query/RepairTodoListQuery.java | 111 + .../devops/repair/entity/Notification.java | 149 + .../youfool/devops/repair/entity/Repair.java | 286 + .../devops/repair/entity/RepairFile.java | 97 + .../devops/repair/entity/RepairHandle.java | 189 + .../devops/repair/entity/RepairLabel.java | 55 + .../devops/repair/entity/RepairSummary.java | 95 + .../devops/repair/entity/RepairTodo.java | 337 + .../excel/CustomRowCellWriteHandler.java | 142 + .../repair/excel/LocalDateTimeConverter.java | 41 + .../devops/repair/excel/RepairTodoExcel.java | 147 + .../repair/mapper/NotificationMapper.java | 23 + .../repair/mapper/RepairFileMapper.java | 16 + .../repair/mapper/RepairHandleMapper.java | 53 + .../repair/mapper/RepairLabelMapper.java | 31 + .../devops/repair/mapper/RepairMapper.java | 25 + .../repair/mapper/RepairSummaryMapper.java | 29 + .../repair/mapper/RepairTodoMapper.java | 52 + .../repair/scheduled/SummaryScheduled.java | 94 + .../repair/service/INotificationService.java | 48 + .../repair/service/IRepairFileService.java | 44 + .../repair/service/IRepairHandleService.java | 63 + .../repair/service/IRepairLabelService.java | 23 + .../devops/repair/service/IRepairService.java | 54 + .../repair/service/IRepairSummaryService.java | 61 + .../repair/service/IRepairTodoService.java | 113 + .../service/impl/NotificationServiceImpl.java | 537 ++ .../service/impl/RepairFileServiceImpl.java | 156 + .../service/impl/RepairHandleServiceImpl.java | 99 + .../service/impl/RepairLabelServiceImpl.java | 64 + .../service/impl/RepairServiceImpl.java | 483 ++ .../impl/RepairSummaryServiceImpl.java | 111 + .../service/impl/RepairTodoServiceImpl.java | 717 ++ .../service/impl/StatisticServiceImpl.java | 286 + .../youfool/devops/util/VerifyCode.java | 76 + .../controller/TestWebSocketController.java | 24 + .../websocket/server/BusinessSysServer.java | 122 + src/main/resources/application-dev.yml | 34 + src/main/resources/application-fs146prod.yml | 34 + src/main/resources/application.yml | 82 + .../excel/shijuyugequbaozhantongji.xlsx | Bin 0 -> 13340 bytes .../resources/excel/tongjineirongxiang.xlsx | Bin 0 -> 9566 bytes .../excel/报障运维单模板.xlsx | Bin 0 -> 13564 bytes src/main/resources/logback-spring.xml | 112 + .../mybatis/mapper/base/DictMapper.xml | 5 + .../mybatis/mapper/base/TaskFileMapper.xml | 5 + .../mybatis/mapper/base/TaskHandleMapper.xml | 10 + .../mybatis/mapper/base/TaskListMapper.xml | 5 + .../mapper/leaderassign/AssignMapper.xml | 93 + .../mybatis/mapper/org/EngineerMapper.xml | 5 + .../mapper/repair/NotificationMapper.xml | 22 + .../mapper/repair/RepairFileMapper.xml | 5 + .../mapper/repair/RepairHandleMapper.xml | 195 + .../mapper/repair/RepairLabelMapper.xml | 135 + .../mybatis/mapper/repair/RepairMapper.xml | 56 + .../mapper/repair/RepairSummaryMapper.xml | 69 + .../mapper/repair/RepairTodoMapper.xml | 290 + src/main/resources/mybatis/mybatis-config.xml | 45 + .../properties/codeCenerator.properties | 22 + .../properties/youfool-devops.properties | 7 + src/main/resources/spring-timer.xml | 18 + src/main/resources/template/daily-report.xlsx | Bin 0 -> 11780 bytes src/main/resources/word/yunWeiTongGao.xml | 3 + .../com/chinaweal/youfool/devops/AppTest.java | 19 + 126 files changed, 17802 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 db/devops.pdma.json create mode 100644 db/加入网办入口.sql create mode 100644 pom.xml create mode 100644 src/main/java/com/chinaweal/youfool/devops/DevOpsApplication.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/base/controller/DictController.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/base/controller/TaskFileController.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/base/controller/TaskHandleController.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/base/controller/TaskListController.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/base/controller/query/BaseListQuery.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/base/entity/Dict.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/base/entity/TaskFile.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/base/entity/TaskHandle.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/base/entity/TaskList.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/base/mapper/DictMapper.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/base/mapper/TaskFileMapper.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/base/mapper/TaskHandleMapper.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/base/mapper/TaskListMapper.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/base/service/IDictService.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/base/service/IMonitorService.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/base/service/ITaskFileService.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/base/service/ITaskHandleService.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/base/service/ITaskListService.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/base/service/impl/DictServiceImpl.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/base/service/impl/MonitorServiceImpl.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/base/service/impl/TaskFileServiceImpl.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/base/service/impl/TaskHandleServiceImpl.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/base/service/impl/TaskListServiceImpl.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/config/CorsConfig.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/config/DevopsDataSource.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/config/FilterConfig.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/config/InterceptorConfig.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/config/PropertySourceConfig.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/config/SchedulingXmlConfig.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/config/SwaggerKnife4j.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/config/YoufoolDataSource.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/dev/MybatisPlusCodeGenerator.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/leaderassign/controller/AssignController.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/leaderassign/controller/dto/AssignHandleQuery.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/leaderassign/controller/dto/TaskAssignVo.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/leaderassign/entity/Assign.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/leaderassign/mapper/AssignMapper.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/leaderassign/service/IAssignService.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/leaderassign/service/impl/AssignServiceImpl.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/org/business/entity/BusinessUser.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/org/business/service/BusinessUserService.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/org/business/service/impl/BusinessUserServiceImpl.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/org/controller/EngineerController.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/org/controller/UserController.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/org/entity/Engineer.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/org/interceptor/LoginInterceptor.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/org/mapper/EngineerMapper.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/org/service/IEngineerService.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/org/service/impl/EngineerServiceImpl.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/api/RobotApi.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/controller/LabelController.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/controller/NotificationController.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/controller/RepairController.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/controller/RepairTodoController.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/controller/StatisticController.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/controller/SummaryController.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/controller/query/RepairTodoListQuery.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/entity/Notification.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/entity/Repair.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/entity/RepairFile.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/entity/RepairHandle.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/entity/RepairLabel.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/entity/RepairSummary.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/entity/RepairTodo.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/excel/CustomRowCellWriteHandler.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/excel/LocalDateTimeConverter.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/excel/RepairTodoExcel.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/mapper/NotificationMapper.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/mapper/RepairFileMapper.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/mapper/RepairHandleMapper.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/mapper/RepairLabelMapper.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/mapper/RepairMapper.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/mapper/RepairSummaryMapper.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/mapper/RepairTodoMapper.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/scheduled/SummaryScheduled.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/service/INotificationService.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/service/IRepairFileService.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/service/IRepairHandleService.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/service/IRepairLabelService.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/service/IRepairService.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/service/IRepairSummaryService.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/service/IRepairTodoService.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/service/impl/NotificationServiceImpl.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/service/impl/RepairFileServiceImpl.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/service/impl/RepairHandleServiceImpl.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/service/impl/RepairLabelServiceImpl.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/service/impl/RepairServiceImpl.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/service/impl/RepairSummaryServiceImpl.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/service/impl/RepairTodoServiceImpl.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/repair/service/impl/StatisticServiceImpl.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/util/VerifyCode.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/websocket/controller/TestWebSocketController.java create mode 100644 src/main/java/com/chinaweal/youfool/devops/websocket/server/BusinessSysServer.java create mode 100644 src/main/resources/application-dev.yml create mode 100644 src/main/resources/application-fs146prod.yml create mode 100644 src/main/resources/application.yml create mode 100644 src/main/resources/excel/shijuyugequbaozhantongji.xlsx create mode 100644 src/main/resources/excel/tongjineirongxiang.xlsx create mode 100644 src/main/resources/excel/报障运维单模板.xlsx create mode 100644 src/main/resources/logback-spring.xml create mode 100644 src/main/resources/mybatis/mapper/base/DictMapper.xml create mode 100644 src/main/resources/mybatis/mapper/base/TaskFileMapper.xml create mode 100644 src/main/resources/mybatis/mapper/base/TaskHandleMapper.xml create mode 100644 src/main/resources/mybatis/mapper/base/TaskListMapper.xml create mode 100644 src/main/resources/mybatis/mapper/leaderassign/AssignMapper.xml create mode 100644 src/main/resources/mybatis/mapper/org/EngineerMapper.xml create mode 100644 src/main/resources/mybatis/mapper/repair/NotificationMapper.xml create mode 100644 src/main/resources/mybatis/mapper/repair/RepairFileMapper.xml create mode 100644 src/main/resources/mybatis/mapper/repair/RepairHandleMapper.xml create mode 100644 src/main/resources/mybatis/mapper/repair/RepairLabelMapper.xml create mode 100644 src/main/resources/mybatis/mapper/repair/RepairMapper.xml create mode 100644 src/main/resources/mybatis/mapper/repair/RepairSummaryMapper.xml create mode 100644 src/main/resources/mybatis/mapper/repair/RepairTodoMapper.xml create mode 100644 src/main/resources/mybatis/mybatis-config.xml create mode 100644 src/main/resources/properties/codeCenerator.properties create mode 100644 src/main/resources/properties/youfool-devops.properties create mode 100644 src/main/resources/spring-timer.xml create mode 100644 src/main/resources/template/daily-report.xlsx create mode 100644 src/main/resources/word/yunWeiTongGao.xml create mode 100644 src/test/java/com/chinaweal/youfool/devops/AppTest.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0721066 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/target/ +/youfool-devops.iml +/.idea/ +*-backup-*.chnr.json +.back_devops \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..c319e8e --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +**运维管理系统(CW)** +**相关文档** + diff --git a/db/devops.pdma.json b/db/devops.pdma.json new file mode 100644 index 0000000..07c29c0 --- /dev/null +++ b/db/devops.pdma.json @@ -0,0 +1,6665 @@ +{ + "name": "devops", + "describe": "运维管理系统", + "avatar": "", + "version": "4.5.1", + "createdTime": "2023-5-19 09:47:50", + "updatedTime": "2023-5-19 09:51:23", + "dbConns": [], + "profile": { + "default": { + "db": "29D1CE08-4C35-4D2D-AAA9-23D93305B52E", + "dbConn": "", + "entityInitFields": [ + { + "defKey": "TENANT_ID", + "defName": "租户号", + "comment": "", + "type": "", + "len": 32, + "scale": "", + "primaryKey": false, + "notNull": false, + "autoIncrement": false, + "defaultValue": "", + "hideInGraph": true, + "domain": "16120F75-6AA7-4483-868D-F07F511BB081", + "refDict": "", + "uiHint": "", + "id": "ADB3AD14-6603-43E2-8261-114E32442B5B" + }, + { + "defKey": "REVISION", + "defName": "乐观锁", + "comment": "", + "domain": "6BC8F04B-6CFA-4995-98D3-318F5CDD774E", + "type": "", + "len": "", + "scale": "", + "primaryKey": false, + "notNull": false, + "autoIncrement": false, + "defaultValue": "", + "hideInGraph": true, + "refDict": "", + "uiHint": "", + "id": "92BF430E-01FA-4AEF-944F-25A142632654" + }, + { + "defKey": "CREATED_BY", + "defName": "创建人", + "comment": "", + "domain": "16120F75-6AA7-4483-868D-F07F511BB081", + "type": "", + "len": 32, + "scale": "", + "primaryKey": false, + "notNull": false, + "autoIncrement": false, + "defaultValue": "", + "hideInGraph": true, + "refDict": "", + "uiHint": "", + "id": "C8BE2C7A-8251-4ADD-BB4F-411C5754DA62" + }, + { + "defKey": "CREATED_TIME", + "defName": "创建时间", + "comment": "", + "domain": "7CFFA0D3-6A93-4DDC-BC10-DF21211064DC", + "type": "", + "len": "", + "scale": "", + "primaryKey": false, + "notNull": false, + "autoIncrement": false, + "defaultValue": "", + "hideInGraph": true, + "refDict": "", + "uiHint": "", + "id": "4E471FD6-3E73-4A90-B660-51598A482409" + }, + { + "defKey": "UPDATED_BY", + "defName": "更新人", + "comment": "", + "domain": "16120F75-6AA7-4483-868D-F07F511BB081", + "type": "", + "len": 32, + "scale": "", + "primaryKey": false, + "notNull": false, + "autoIncrement": false, + "defaultValue": "", + "hideInGraph": true, + "refDict": "", + "uiHint": "", + "id": "0DC24AA9-4CD0-45D8-95CF-FA546BE343AB" + }, + { + "defKey": "UPDATED_TIME", + "defName": "更新时间", + "comment": "", + "domain": "7CFFA0D3-6A93-4DDC-BC10-DF21211064DC", + "type": "", + "len": "", + "scale": "", + "primaryKey": false, + "notNull": false, + "autoIncrement": false, + "defaultValue": "", + "hideInGraph": true, + "refDict": "", + "uiHint": "", + "id": "09F64AC4-4DEE-428F-AF64-4C103884E1AC" + } + ], + "entityInitProperties": { + "partitioned by": "(date string)", + "row format delimited": "", + "fields terminated by ','": "", + "collection items terminated by '-'": "", + "map keys terminated by ':'": "", + "store as textfile;": "" + } + }, + "javaHome": "", + "sql": { + "delimiter": "" + }, + "dataTypeSupports": [ + { + "defKey": "MYSQL", + "id": "29D1CE08-4C35-4D2D-AAA9-23D93305B52E" + }, + { + "defKey": "ORACLE", + "id": "A4E23CB7-BB01-4BD1-9F71-F73F3E15A542" + }, + { + "defKey": "SQLServer", + "id": "BFC87171-C74F-494A-B7C2-76B9C55FACC9" + }, + { + "defKey": "PostgreSQL", + "id": "DFBEC1DD-AA84-456E-BBF3-C95DD0DB2022" + }, + { + "defKey": "DB2", + "id": "89504F5D-94BF-4C9E-8B2E-44F37305FED5" + }, + { + "defKey": "DM", + "id": "0BBCABA5-B8E4-41B0-B8E4-8F5EA6029307" + }, + { + "defKey": "GaussDB", + "id": "592C7013-143D-4E7B-AF64-0D7BF1E28230" + }, + { + "defKey": "Kingbase", + "id": "77BD85E5-9D0D-4096-8427-CBA306FC9C6A" + }, + { + "defKey": "GBase", + "id": "56F4B55B-F0B8-4049-9E6B-50B95C1D793A" + }, + { + "defKey": "MaxCompute", + "id": "11D1FB71-A587-4217-89BA-611B8A1F83E0" + }, + { + "defKey": "SQLite", + "id": "B363BE0B-F852-49B8-9B2E-F6D2174DEAC1" + }, + { + "defKey": "Hive", + "id": "81CCA482-3F4D-4EAC-8CF9-F5E7BC098AD2" + }, + { + "defKey": "JAVA", + "id": "797A1496-D649-4261-89B4-544132EC3F36" + }, + { + "defKey": "JavaMybatis", + "id": "895CFD1D-4273-4D32-A2C4-CAC70200AB5B" + }, + { + "defKey": "JavaMybatisPlus", + "id": "A2EE7B4A-CE62-4290-B00C-B26C1BF18073" + }, + { + "defKey": "C#", + "id": "F3AC2415-E86B-40C6-9FEB-F4B7937D2C30" + }, + { + "defKey": "Golang", + "id": "B91D99E0-9B7C-416C-8737-B760957DAF09" + }, + { + "defKey": "Rust", + "id": "BDF457FD-9F98-4AC3-A705-7587B00A3BAB" + }, + { + "defKey": "Doris", + "id": "483F9346-C99E-4014-A1D2-A554606BD8A3" + } + ], + "codeTemplates": [ + { + "type": "appCode", + "applyFor": "797A1496-D649-4261-89B4-544132EC3F36", + " JpaBean": "{{ var today=new Date();\n var fullYear=today.getFullYear();\n var month=today.getMonth() + 1;\n var days=today.getDate();\n \n var pkVarName = \"undefinedId\";\n var pkDataType = \"String\";\n it.entity.fields.forEach(function(field){\n if(field.primaryKey){\n pkVarName = it.func.camel(field.defKey,false);\n pkDataType = field[\"type\"];\n return;\n }\n });\n \n var pkgName = it.entity.env.base.nameSpace;\n var beanClass = it.entity.env.base.codeRoot;\n var beanVarName = beanClass.charAt(0).toLowerCase()+beanClass.slice(1);\n var serviceClass = beanClass+'Service';\n var serviceVarName= beanVarName+'Service';\n \n}}package {{=pkgName}}.entity;\n$blankline\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;\nimport javax.persistence.*;\nimport java.io.Serializable;\nimport java.util.Date;\n$blankline\n\n /**\n * {{=it.entity.defName}};{{=it.entity.comment}}\n * @author : http://www.chiner.pro\n * @date : {{=fullYear}}-{{=month}}-{{=days}}\n */\n@ApiModel(value = \"{{=it.entity.defName}}\",description = \"{{=it.entity.comment}}\")\n@Table(name=\"{{=it.entity.defKey}}\")\npublic class {{=beanClass}} implements Serializable,Cloneable{\n{{~it.entity.fields:field:index}}\n /** {{=it.func.join(field.defName,field.comment,';')}} */\n {{? field.primaryKey }}\n @Id\n @GeneratedValue\n {{?}}\n @ApiModelProperty(name = \"{{=field.defName}}\",notes = \"{{=field.comment}}\")\n private {{=field.type}} {{=it.func.camel(field.defKey,false)}} ;\n{{~}}\n$blankline\n\n{{~it.entity.fields:field:index}}\n /** {{=it.func.join(field.defName,field.comment,';')}} */\n public {{=field.type}} get{{=it.func.camel(field.defKey,true)}}(){\n return this.{{=it.func.camel(field.defKey,false)}};\n }\n /** {{=it.func.join(field.defName,field.comment,';')}} */\n public void set{{=it.func.camel(field.defKey,true)}}({{=field.type}} {{= it.func.camel(field.defKey,false) }}){\n this.{{=it.func.camel(field.defKey,false)}}={{=it.func.camel(field.defKey,false)}};\n }\n{{~}}\n}" + }, + { + "type": "appCode", + "applyFor": "F3AC2415-E86B-40C6-9FEB-F4B7937D2C30", + "Default": "using System;\nusing System.Collections.Generic;\n\n$blankline\n{{\n var today=new Date();\n var fullYear=today.getFullYear();\n var month=today.getMonth() + 1;\n var days=today.getDate();\n}}\n/*\n * @author : http://www.chiner.com.cn\n * @date : {{=fullYear}}-{{=month}}-{{=days}}\n * @desc : {{=it.func.join(it.entity.defName,it.entity.comment,'-')}}\n */\nnamespace PDManer.Application\n{\n public partial class {{=it.func.camel(it.entity.defKey,true) }}\n {\n \n {{~it.entity.fields:field:index}}\n /// \n /// {{=it.func.join(field.defName,field.comment,';')}}\n /// \n public {{=field.type}} {{=it.func.camel(field.defKey,true)}} { get; set; }\n $blankline\n {{~}}\n \n }\n}", + "SqlSugar": "using System;\nusing System.Collections.Generic;\nusing SqlSugar;\n\n$blankline\n{{\n var today=new Date();\n var fullYear=today.getFullYear();\n var month=today.getMonth() + 1;\n var days=today.getDate();\n var sqlSugartable='[SugarTable(\"{{=it.entity.defKey}}\", TableDescription = \"{{=it.func.join(it.entity.defName,it.entity.comment,';')}}\")]';\n}}\n/*\n * @author : xkdong@163.com\n * @date : {{=fullYear}}-{{=month}}-{{=days}}\n * @desc : {{=it.func.join(it.entity.defName,it.entity.comment,'-')}}\n */\nnamespace Model.DBModel\n{\n /// \n /// {{=it.func.join(it.entity.defName,it.entity.comment,';')}}\n /// \n {{=sqlSugartable}}\n public class {{=it.entity.defKey}}\n {\n {{~it.entity.fields:field:index}}\n /// \n /// {{=it.func.join(field.defName,field.comment,';')}}\n /// \n {{? field.primaryKey }}\n [SugarColumn(IsIdentity = true, IsPrimaryKey = true)]\n {{?}}\n public {{=field.type}} {{=it.func.camel(field.defKey,true)}}{ get; set; }\n $blankline\n {{~}}\n }\n}" + }, + { + "applyFor": "895CFD1D-4273-4D32-A2C4-CAC70200AB5B", + "type": "appCode", + "Controller": "{{ var today=new Date();\n var fullYear=today.getFullYear();\n var month=today.getMonth() + 1;\n var days=today.getDate();\n \n var pkVarName = \"undefinedId\";\n var pkDataType = \"String\";\n it.entity.fields.forEach(function(field){\n if(field.primaryKey){\n pkVarName = it.func.camel(field.defKey,false);\n pkDataType = field[\"type\"];\n return;\n }\n });\n \n var pkgName = it.entity.env.base.nameSpace;\n var beanClass = it.entity.env.base.codeRoot;\n var beanVarName = beanClass.charAt(0).toLowerCase()+beanClass.slice(1);\n var serviceClass = beanClass+'Service';\n var serviceVarName= beanVarName+'Service';\n \n}}package {{=pkgName}}.controller;\n$blankline\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.web.bind.annotation.*;\nimport {{=pkgName}}.entity.{{=beanClass}};\nimport {{=pkgName}}.service.{{=serviceClass}};\n$blankline\n\n /**\n * {{=it.entity.defName}};({{=it.entity.defKey}})表控制层\n * @author : http://www.chiner.pro\n * @date : {{=fullYear}}-{{=month}}-{{=days}}\n */\n@Api(tags = \"{{=it.entity.defName}}对象功能接口\")\n@RestController\n@RequestMapping(\"/{{=it.func.camel(it.entity.defKey,false)}}\")\npublic class {{=beanClass}}Controller{\n @Autowired\n private {{=serviceClass}} {{=serviceVarName}};\n $blankline\n /** \n * 通过ID查询单条数据 \n *\n * @param {{=pkVarName}} 主键\n * @return 实例对象\n */\n @ApiOperation(\"通过ID查询单条数据\")\n @GetMapping(\"{{{=it.func.camel(pkVarName,false)}}}\")\n public ResponseEntity<{{=beanClass}}> queryById({{=pkDataType}} {{=pkVarName}}){\n return ResponseEntity.ok({{=serviceVarName}}.queryById({{=pkVarName}}));\n }\n $blankline\n /** \n * 分页查询\n *\n * @param {{=beanVarName}} 筛选条件\n * @param pageRequest 分页对象\n * @return 查询结果\n */\n @ApiOperation(\"分页查询\")\n @GetMapping\n public ResponseEntity> paginQuery({{=beanClass}} {{=beanVarName}}, PageRequest pageRequest){\n return ResponseEntity.ok({{=serviceVarName}}.paginQuery({{=beanVarName}}, pageRequest));\n }\n $blankline\n /** \n * 新增数据\n *\n * @param {{=beanVarName}} 实例对象\n * @return 实例对象\n */\n @ApiOperation(\"新增数据\")\n @PostMapping\n public ResponseEntity<{{=beanClass}}> add({{=beanClass}} {{=beanVarName}}){\n return ResponseEntity.ok({{=serviceVarName}}.insert({{=beanVarName}}));\n }\n $blankline\n /** \n * 更新数据\n *\n * @param {{=beanVarName}} 实例对象\n * @return 实例对象\n */\n @ApiOperation(\"更新数据\")\n @PutMapping\n public ResponseEntity<{{=beanClass}}> edit({{=beanClass}} {{=beanVarName}}){\n return ResponseEntity.ok({{=serviceVarName}}.update({{=beanVarName}}));\n }\n $blankline\n /** \n * 通过主键删除数据\n *\n * @param {{=pkVarName}} 主键\n * @return 是否成功\n */\n @ApiOperation(\"通过主键删除数据\")\n @DeleteMapping\n public ResponseEntity deleteById({{=pkDataType}} {{=pkVarName}}){\n return ResponseEntity.ok({{=serviceVarName}}.deleteById({{=pkVarName}}));\n }\n}", + "Service": "{{ var today=new Date();\n var fullYear=today.getFullYear();\n var month=today.getMonth() + 1;\n var days=today.getDate();\n \n var pkVarName = \"undefinedId\";\n var pkDataType = \"String\";\n it.entity.fields.forEach(function(field){\n if(field.primaryKey){\n pkVarName = it.func.camel(field.defKey,false);\n pkDataType = field[\"type\"];\n return;\n }\n });\n \n var pkgName = it.entity.env.base.nameSpace;\n var beanClass = it.entity.env.base.codeRoot;\n var beanVarName = beanClass.charAt(0).toLowerCase()+beanClass.slice(1);\n var serviceClass = beanClass+'Service';\n var serviceVarName= beanVarName+'Service';\n \n}}package {{=pkgName}}.service;\n$blankline\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.PageRequest;\nimport {{=pkgName}}.entity.{{=beanClass}};\n$blankline\n\n /**\n * {{=it.entity.defName}};({{=it.entity.defKey}})表服务接口\n * @author : http://www.chiner.pro\n * @date : {{=fullYear}}-{{=month}}-{{=days}}\n */\npublic interface {{=serviceClass}}{\n /** \n * 通过ID查询单条数据 \n *\n * @param {{=pkVarName}} 主键\n * @return 实例对象\n */\n {{=beanClass}} queryById({{=pkDataType}} {{=pkVarName}});\n \n /** \n * 分页查询\n *\n * @param {{=beanVarName}} 筛选条件\n * @param pageRequest 分页对象\n * @return 查询结果\n */\n Page<{{=beanClass}}> paginQuery({{=beanClass}} {{=beanVarName}}, PageRequest pageRequest);\n\n /** \n * 新增数据\n *\n * @param {{=beanVarName}} 实例对象\n * @return 实例对象\n */\n {{=beanClass}} insert({{=beanClass}} {{=beanVarName}});\n\n \n /** \n * 更新数据\n *\n * @param {{=beanVarName}} 实例对象\n * @return 实例对象\n */\n {{=beanClass}} update({{=beanClass}} {{=beanVarName}});\n\n /** \n * 通过主键删除数据\n *\n * @param {{=pkVarName}} 主键\n * @return 是否成功\n */\n boolean deleteById({{=pkDataType}} {{=pkVarName}});\n}", + "ServiceImpl": "{{ var today=new Date();\n var fullYear=today.getFullYear();\n var month=today.getMonth() + 1;\n var days=today.getDate();\n \n var pkVarName = \"undefinedId\";\n var pkVarNameU = \"UndefinedId\";\n var pkDataType = \"String\";\n it.entity.fields.forEach(function(field){\n if(field.primaryKey){\n pkVarName = it.func.camel(field.defKey,false);\n pkVarNameU = it.func.camel(field.defKey,true);\n pkDataType = field[\"type\"];\n return;\n }\n });\n \n var pkgName = it.entity.env.base.nameSpace;\n var beanClass = it.entity.env.base.codeRoot;\n var beanVarName = beanClass.charAt(0).toLowerCase()+beanClass.slice(1);\n var serviceClass = beanClass+'Service';\n var serviceVarName= beanVarName+'Service';\n var mapperName = beanVarName+'Mapper';\n \n}}package {{=pkgName}}.service.impl;\n$blankline\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.PageImpl;\nimport org.springframework.data.domain.PageRequest;\nimport {{=pkgName}}.entity.{{=beanClass}};\nimport {{=pkgName}}.mapper.{{=beanClass}}Mapper;\nimport {{=pkgName}}.service.{{=serviceClass}};\n\n /**\n * {{=it.entity.defName}};({{=it.entity.defKey}})表服务实现类\n * @author : http://www.chiner.pro\n * @date : {{=fullYear}}-{{=month}}-{{=days}}\n */\n@Service\npublic class {{=serviceClass}}Impl implements {{=serviceClass}}{\n @Autowired\n private {{=beanClass}}Mapper {{=mapperName}};\n $blankline\n /** \n * 通过ID查询单条数据 \n *\n * @param {{=pkVarName}} 主键\n * @return 实例对象\n */\n public {{=beanClass}} queryById({{=pkDataType}} {{=pkVarName}}){\n return {{=mapperName}}.queryById({{=pkVarName}});\n }\n $blankline\n /** \n * 分页查询\n *\n * @param {{=beanVarName}} 筛选条件\n * @param pageRequest 分页对象\n * @return 查询结果\n */\n public Page<{{=beanClass}}> paginQuery({{=beanClass}} {{=beanVarName}}, PageRequest pageRequest){\n long total = {{=mapperName}}.count({{=beanVarName}});\n return new PageImpl<>({{=mapperName}}.queryAllByLimit({{=beanVarName}}, pageRequest), pageRequest, total);\n }\n $blankline\n /** \n * 新增数据\n *\n * @param {{=beanVarName}} 实例对象\n * @return 实例对象\n */\n public {{=beanClass}} insert({{=beanClass}} {{=beanVarName}}){\n {{=mapperName}}.insert({{=beanVarName}});\n return {{=beanVarName}};\n }\n $blankline\n /** \n * 更新数据\n *\n * @param {{=beanVarName}} 实例对象\n * @return 实例对象\n */\n public {{=beanClass}} update({{=beanClass}} {{=beanVarName}}){\n {{=mapperName}}.update({{=beanVarName}});\n return queryById({{=beanVarName}}.get{{=pkVarNameU}}());\n }\n $blankline\n /** \n * 通过主键删除数据\n *\n * @param {{=pkVarName}} 主键\n * @return 是否成功\n */\n public boolean deleteById({{=pkDataType}} {{=pkVarName}}){\n int total = {{=mapperName}}.deleteById({{=pkVarName}});\n return total > 0;\n }\n}", + "Mapper": "{{ var today=new Date();\n var fullYear=today.getFullYear();\n var month=today.getMonth() + 1;\n var days=today.getDate();\n \n var pkVarName = \"undefinedId\";\n var pkDataType = \"String\";\n it.entity.fields.forEach(function(field){\n if(field.primaryKey){\n pkVarName = it.func.camel(field.defKey,false);\n pkDataType = field[\"type\"];\n return;\n }\n });\n \n var pkgName = it.entity.env.base.nameSpace;\n var beanClass = it.entity.env.base.codeRoot;\n var beanVarName = beanClass.charAt(0).toLowerCase()+beanClass.slice(1);\n var serviceClass = beanClass+'Service';\n var serviceVarName= beanVarName+'Service';\n \n}}package {{=pkgName}}.mapper;\n$blankline\nimport java.util.List;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Param;\nimport org.springframework.data.domain.Pageable;\nimport {{=pkgName}}.entity.{{=beanClass}};\n$blankline\n\n /**\n * {{=it.entity.defName}};({{=it.entity.defKey}})表数据库访问层\n * @author : http://www.chiner.pro\n * @date : {{=fullYear}}-{{=month}}-{{=days}}\n */\n@Mapper\npublic interface {{=beanClass}}Mapper{\n /** \n * 通过ID查询单条数据 \n *\n * @param {{=pkVarName}} 主键\n * @return 实例对象\n */\n {{=beanClass}} queryById({{=pkDataType}} {{=pkVarName}});\n \n /** \n * 分页查询指定行数据\n *\n * @param {{=beanVarName}} 查询条件\n * @param pageable 分页对象\n * @return 对象列表\n */\n List<{{=beanClass}}> queryAllByLimit({{=beanClass}} {{=beanVarName}}, @Param(\"pageable\") Pageable pageable);\n\n /** \n * 统计总行数\n *\n * @param {{=beanVarName}} 查询条件\n * @return 总行数\n */\n long count({{=beanClass}} {{=beanVarName}});\n\n /** \n * 新增数据\n *\n * @param {{=beanVarName}} 实例对象\n * @return 影响行数\n */\n int insert({{=beanClass}} {{=beanVarName}});\n\n /** \n * 批量新增数据\n *\n * @param entities List<{{=beanClass}}> 实例对象列表\n * @return 影响行数\n */\n int insertBatch(@Param(\"entities\") List<{{=beanClass}}> entities);\n \n /** \n * 批量新增或按主键更新数据\n *\n * @param entities List<{{=beanClass}}> 实例对象列表\n * @return 影响行数\n */\n int insertOrUpdateBatch(@Param(\"entities\") List<{{=beanClass}}> entities);\n \n /** \n * 更新数据\n *\n * @param {{=beanVarName}} 实例对象\n * @return 影响行数\n */\n int update({{=beanClass}} {{=beanVarName}});\n\n /** \n * 通过主键删除数据\n *\n * @param {{=pkVarName}} 主键\n * @return 影响行数\n */\n int deleteById({{=pkDataType}} {{=pkVarName}});\n}", + "Mapper.xml": "{{ var today=new Date();\n var fullYear=today.getFullYear();\n var month=today.getMonth() + 1;\n var days=today.getDate();\n \n var pkVarName = \"undefinedId\";\n var pkDataType = \"String\";\n var pkField = \"UNDEFINED_ID\";\n it.entity.fields.forEach(function(field){\n if(field.primaryKey){\n pkField = field.defKey;\n pkVarName = it.func.camel(field.defKey,false);\n pkDataType = field[\"type\"];\n return;\n }\n });\n \n var pkgName = it.entity.env.base.nameSpace;\n var beanClass = it.entity.env.base.codeRoot;\n var beanVarName = beanClass.charAt(0).toLowerCase()+beanClass.slice(1);\n var serviceClass = beanClass+'Service';\n var serviceVarName= beanVarName+'Service';\n \n}}\n\n\n \n {{~it.entity.fields:field:index}}\n \n {{~}}\n \n $blankline\n \n \n $blankline\n \n \n $blankline\n \n \n $blankline\n \n \n insert into {{=it.entity.defKey}}({{=it.entity.fields.map(function(e,i){return e.defKey}).join(',')}})\n values ({{=it.entity.fields.map(function(e,i){return '#{'+it.func.camel(e.defKey,false)+'}'}).join(',')}})\n \n $blankline\n \n \n insert into {{=it.entity.defKey}}({{=it.entity.fields.map(function(e,i){return e.defKey}).join(',')}})\n values\n \n ({{=it.entity.fields.map(function(e,i){return '#{entity.'+it.func.camel(e.defKey,false)+'}'}).join(',')}})\n \n \n $blankline\n \n \n insert into {{=it.entity.defKey}}({{=it.entity.fields.map(function(e,i){return e.defKey}).join(',')}})\n values\n \n ({{=it.entity.fields.map(function(e,i){return '#{entity.'+it.func.camel(e.defKey,false)+'}'}).join(',')}})\n \n on duplicate key update\n {{=it.entity.fields.map(function(e,i){return e.defKey + '=values('+e.defKey+')'}).join(',\\n\\t\\t')}}\n \n $blankline\n \n \n update {{=it.entity.defKey}}\n \n {{~it.entity.fields:field:index}}\n \n {{=field.defKey}} = #{{{=it.func.camel(field.defKey,false)}}},\n \n {{~}}\n \n where {{=pkField}} = #{{{=pkVarName}}}\n \n $blankline\n \n \n delete from {{=it.entity.defKey}} where {{=pkField}} = #{{{=pkVarName}}}\n \n\n\n", + "Entity": "{{ var today=new Date();\n var fullYear=today.getFullYear();\n var month=today.getMonth() + 1;\n var days=today.getDate();\n \n var pkVarName = \"undefinedId\";\n var pkDataType = \"String\";\n it.entity.fields.forEach(function(field){\n if(field.primaryKey){\n pkVarName = it.func.camel(field.defKey,false);\n pkDataType = field[\"type\"];\n return;\n }\n });\n \n var pkgName = it.entity.env.base.nameSpace;\n var beanClass = it.entity.env.base.codeRoot;\n var beanVarName = beanClass.charAt(0).toLowerCase()+beanClass.slice(1);\n var serviceClass = beanClass+'Service';\n var serviceVarName= beanVarName+'Service';\n \n}}package {{=pkgName}}.entity;\n$blankline\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;\nimport java.io.Serializable;\nimport java.util.Date;\n$blankline\n\n /**\n * {{=it.entity.defName}};{{=it.entity.comment}}\n * @author : http://www.chiner.pro\n * @date : {{=fullYear}}-{{=month}}-{{=days}}\n */\n@ApiModel(value = \"{{=it.entity.defName}}\",description = \"{{=it.entity.comment}}\")\npublic class {{=beanClass}} implements Serializable,Cloneable{\n{{~it.entity.fields:field:index}}\n /** {{=it.func.join(field.defName,field.comment,';')}} */\n @ApiModelProperty(name = \"{{=field.defName}}\",notes = \"{{=field.comment}}\")\n private {{=field.type}} {{=it.func.camel(field.defKey,false)}} ;\n{{~}}\n$blankline\n\n{{~it.entity.fields:field:index}}\n /** {{=it.func.join(field.defName,field.comment,';')}} */\n public {{=field.type}} get{{=it.func.camel(field.defKey,true)}}(){\n return this.{{=it.func.camel(field.defKey,false)}};\n }\n /** {{=it.func.join(field.defName,field.comment,';')}} */\n public void set{{=it.func.camel(field.defKey,true)}}({{=field.type}} {{= it.func.camel(field.defKey,false) }}){\n this.{{=it.func.camel(field.defKey,false)}}={{=it.func.camel(field.defKey,false)}};\n }\n{{~}}\n}" + }, + { + "applyFor": "A2EE7B4A-CE62-4290-B00C-B26C1BF18073", + "type": "appCode", + "Controller": "{{ var today=new Date();\n var fullYear=today.getFullYear();\n var month=today.getMonth() + 1;\n var days=today.getDate();\n \n var pkVarName = \"undefinedId\";\n var pkDataType = \"String\";\n it.entity.fields.forEach(function(field){\n if(field.primaryKey){\n pkVarName = it.func.camel(field.defKey,false);\n pkDataType = field[\"type\"];\n return;\n }\n });\n \n var pkgName = it.entity.env.base.nameSpace;\n var beanClass = it.entity.env.base.codeRoot;\n var beanVarName = beanClass.charAt(0).toLowerCase()+beanClass.slice(1);\n var serviceClass = beanClass+'Service';\n var serviceVarName= beanVarName+'Service';\n \n}}package {{=pkgName}}.controller;\n$blankline\nimport java.util.List;\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.domain.PageImpl;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.web.bind.annotation.*;\nimport {{=pkgName}}.entity.{{=beanClass}};\nimport {{=pkgName}}.service.{{=serviceClass}};\n$blankline\n\n /**\n * {{=it.entity.defName}};({{=it.entity.defKey}})表控制层\n * @author : http://www.chiner.pro\n * @date : {{=fullYear}}-{{=month}}-{{=days}}\n */\n@Api(tags = \"{{=it.entity.defName}}对象功能接口\")\n@RestController\n@RequestMapping(\"/{{=it.func.camel(it.entity.defKey,false)}}\")\npublic class {{=beanClass}}Controller{\n @Autowired\n private {{=serviceClass}} {{=serviceVarName}};\n $blankline\n /** \n * 通过ID查询单条数据 \n *\n * @param {{=pkVarName}} 主键\n * @return 实例对象\n */\n @ApiOperation(\"通过ID查询单条数据\")\n @GetMapping(\"{{{=it.func.camel(pkVarName,false)}}}\")\n public ResponseEntity<{{=beanClass}}> queryById({{=pkDataType}} {{=pkVarName}}){\n return ResponseEntity.ok({{=serviceVarName}}.queryById({{=pkVarName}}));\n }\n $blankline\n /** \n * 分页查询\n *\n * @param {{=beanVarName}} 筛选条件\n * @param pageRequest 分页对象\n * @return 查询结果\n */\n @ApiOperation(\"分页查询\")\n @GetMapping\n public ResponseEntity> paginQuery({{=beanClass}} {{=beanVarName}}, PageRequest pageRequest){\n //1.分页参数\n long current = pageRequest.getPageNumber();\n long size = pageRequest.getPageSize();\n\n //2.分页查询\n /*把Mybatis的分页对象做封装转换,MP的分页对象上有一些SQL敏感信息,还是通过spring的分页模型来封装数据吧*/\n com.baomidou.mybatisplus.extension.plugins.pagination.Page<{{=beanClass}}> pageResult = {{=serviceVarName}}.paginQuery({{=beanVarName}}, current,size);\n\n //3. 分页结果组装\n List<{{=beanClass}}> dataList = pageResult.getRecords();\n long total = pageResult.getTotal();\n PageImpl<{{=beanClass}}> retPage = new PageImpl<{{=beanClass}}>(dataList,pageRequest,total);\n return ResponseEntity.ok(retPage);\n }\n $blankline\n /** \n * 新增数据\n *\n * @param {{=beanVarName}} 实例对象\n * @return 实例对象\n */\n @ApiOperation(\"新增数据\")\n @PostMapping\n public ResponseEntity<{{=beanClass}}> add({{=beanClass}} {{=beanVarName}}){\n return ResponseEntity.ok({{=serviceVarName}}.insert({{=beanVarName}}));\n }\n $blankline\n /** \n * 更新数据\n *\n * @param {{=beanVarName}} 实例对象\n * @return 实例对象\n */\n @ApiOperation(\"更新数据\")\n @PutMapping\n public ResponseEntity<{{=beanClass}}> edit({{=beanClass}} {{=beanVarName}}){\n return ResponseEntity.ok({{=serviceVarName}}.update({{=beanVarName}}));\n }\n $blankline\n /** \n * 通过主键删除数据\n *\n * @param {{=pkVarName}} 主键\n * @return 是否成功\n */\n @ApiOperation(\"通过主键删除数据\")\n @DeleteMapping\n public ResponseEntity deleteById({{=pkDataType}} {{=pkVarName}}){\n return ResponseEntity.ok({{=serviceVarName}}.deleteById({{=pkVarName}}));\n }\n}", + "Service": "{{ var today=new Date();\n var fullYear=today.getFullYear();\n var month=today.getMonth() + 1;\n var days=today.getDate();\n \n var pkVarName = \"undefinedId\";\n var pkDataType = \"String\";\n it.entity.fields.forEach(function(field){\n if(field.primaryKey){\n pkVarName = it.func.camel(field.defKey,false);\n pkDataType = field[\"type\"];\n return;\n }\n });\n \n var pkgName = it.entity.env.base.nameSpace;\n var beanClass = it.entity.env.base.codeRoot;\n var beanVarName = beanClass.charAt(0).toLowerCase()+beanClass.slice(1);\n var serviceClass = beanClass+'Service';\n var serviceVarName= beanVarName+'Service';\n \n}}package {{=pkgName}}.service;\n$blankline\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport {{=pkgName}}.entity.{{=beanClass}};\n$blankline\n\n /**\n * {{=it.entity.defName}};({{=it.entity.defKey}})表服务接口\n * @author : http://www.chiner.pro\n * @date : {{=fullYear}}-{{=month}}-{{=days}}\n */\npublic interface {{=serviceClass}}{\n $blankline\n /** \n * 通过ID查询单条数据 \n *\n * @param {{=pkVarName}} 主键\n * @return 实例对象\n */\n {{=beanClass}} queryById({{=pkDataType}} {{=pkVarName}});\n $blankline\n /**\n * 分页查询\n *\n * @param {{=beanVarName}} 筛选条件\n * @param current 当前页码\n * @param size 每页大小\n * @return\n */\n Page<{{=beanClass}}> paginQuery({{=beanClass}} {{=beanVarName}}, long current, long size);\n\n /** \n * 新增数据\n *\n * @param {{=beanVarName}} 实例对象\n * @return 实例对象\n */\n {{=beanClass}} insert({{=beanClass}} {{=beanVarName}});\n\n \n /** \n * 更新数据\n *\n * @param {{=beanVarName}} 实例对象\n * @return 实例对象\n */\n {{=beanClass}} update({{=beanClass}} {{=beanVarName}});\n\n /** \n * 通过主键删除数据\n *\n * @param {{=pkVarName}} 主键\n * @return 是否成功\n */\n boolean deleteById({{=pkDataType}} {{=pkVarName}});\n}", + "ServiceImpl": "{{ var today=new Date();\n var fullYear=today.getFullYear();\n var month=today.getMonth() + 1;\n var days=today.getDate();\n \n var pkVarName = \"undefinedId\";\n var pkVarNameU = \"UndefinedId\";\n var pkFieldKey = \"UNDEFINED\";\n var pkDataType = \"String\";\n it.entity.fields.forEach(function(field){\n if(field.primaryKey){\n pkFieldKey = field.defKey;\n pkVarName = it.func.camel(field.defKey,false);\n pkVarNameU = it.func.camel(field.defKey,true);\n pkDataType = field[\"type\"];\n return;\n }\n });\n \n var pkgName = it.entity.env.base.nameSpace;\n var beanClass = it.entity.env.base.codeRoot;\n var beanVarName = beanClass.charAt(0).toLowerCase()+beanClass.slice(1);\n var serviceClass = beanClass+'Service';\n var serviceVarName= beanVarName+'Service';\n var mapperName = beanVarName+'Mapper';\n \n}}package {{=pkgName}}.service.impl;\n$blankline\nimport cn.hutool.core.util.StrUtil;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;\n\nimport {{=pkgName}}.entity.{{=beanClass}};\nimport {{=pkgName}}.mapper.{{=beanClass}}Mapper;\nimport {{=pkgName}}.service.{{=serviceClass}};\n\n /**\n * {{=it.entity.defName}};({{=it.entity.defKey}})表服务实现类\n * @author : http://www.chiner.pro\n * @date : {{=fullYear}}-{{=month}}-{{=days}}\n */\n@Service\npublic class {{=serviceClass}}Impl implements {{=serviceClass}}{\n @Autowired\n private {{=beanClass}}Mapper {{=mapperName}};\n $blankline\n /** \n * 通过ID查询单条数据 \n *\n * @param {{=pkVarName}} 主键\n * @return 实例对象\n */\n public {{=beanClass}} queryById({{=pkDataType}} {{=pkVarName}}){\n return {{=mapperName}}.selectById({{=pkVarName}});\n }\n $blankline\n /**\n * 分页查询\n *\n * @param {{=beanVarName}} 筛选条件\n * @param current 当前页码\n * @param size 每页大小\n * @return\n */\n public Page<{{=beanClass}}> paginQuery({{=beanClass}} {{=beanVarName}}, long current, long size){\n //1. 构建动态查询条件\n LambdaQueryWrapper<{{=beanClass}}> queryWrapper = new LambdaQueryWrapper<>();\n {{~it.entity.fields.filter(function(e){return e[\"type\"]===\"String\"&&e.defKey !== pkFieldKey}):field:index}}\n if(StrUtil.isNotBlank({{=beanVarName}}.get{{=it.func.camel(field.defKey,true)}}())){\n queryWrapper.eq({{=beanClass}}::get{{=it.func.camel(field.defKey,true)}}, {{=beanVarName}}.get{{=it.func.camel(field.defKey,true)}}());\n }\n {{~}}\n\n //2. 执行分页查询\n Page<{{=beanClass}}> pagin = new Page<>(current , size , true);\n IPage<{{=beanClass}}> selectResult = {{=mapperName}}.selectByPage(pagin , queryWrapper);\n pagin.setPages(selectResult.getPages());\n pagin.setTotal(selectResult.getTotal());\n pagin.setRecords(selectResult.getRecords());\n\n //3. 返回结果\n return pagin;\n }\n $blankline\n /** \n * 新增数据\n *\n * @param {{=beanVarName}} 实例对象\n * @return 实例对象\n */\n public {{=beanClass}} insert({{=beanClass}} {{=beanVarName}}){\n {{=mapperName}}.insert({{=beanVarName}});\n return {{=beanVarName}};\n }\n $blankline\n /** \n * 更新数据\n *\n * @param {{=beanVarName}} 实例对象\n * @return 实例对象\n */\n public {{=beanClass}} update({{=beanClass}} {{=beanVarName}}){\n //1. 根据条件动态更新\n LambdaUpdateChainWrapper<{{=beanClass}}> chainWrapper = new LambdaUpdateChainWrapper<{{=beanClass}}>({{=mapperName}});\n {{~it.entity.fields.filter(function(e){return e[\"type\"]===\"String\"&&e.defKey !== pkFieldKey}):field:index}}\n if(StrUtil.isNotBlank({{=beanVarName}}.get{{=it.func.camel(field.defKey,true)}}())){\n chainWrapper.eq({{=beanClass}}::get{{=it.func.camel(field.defKey,true)}}, {{=beanVarName}}.get{{=it.func.camel(field.defKey,true)}}());\n }\n {{~}}\n //2. 设置主键,并更新\n chainWrapper.set({{=beanClass}}::get{{=pkVarNameU}}, {{=beanVarName}}.get{{=pkVarNameU}}());\n boolean ret = chainWrapper.update();\n //3. 更新成功了,查询最最对象返回\n if(ret){\n return queryById({{=beanVarName}}.get{{=pkVarNameU}}());\n }else{\n return {{=beanVarName}};\n }\n }\n $blankline\n /** \n * 通过主键删除数据\n *\n * @param {{=pkVarName}} 主键\n * @return 是否成功\n */\n public boolean deleteById({{=pkDataType}} {{=pkVarName}}){\n int total = {{=mapperName}}.deleteById({{=pkVarName}});\n return total > 0;\n }\n}", + "Mapper": "{{ var today=new Date();\n var fullYear=today.getFullYear();\n var month=today.getMonth() + 1;\n var days=today.getDate();\n \n var pkVarName = \"undefinedId\";\n var pkDataType = \"String\";\n it.entity.fields.forEach(function(field){\n if(field.primaryKey){\n pkVarName = it.func.camel(field.defKey,false);\n pkDataType = field[\"type\"];\n return;\n }\n });\n \n var pkgName = it.entity.env.base.nameSpace;\n var beanClass = it.entity.env.base.codeRoot;\n var beanVarName = beanClass.charAt(0).toLowerCase()+beanClass.slice(1);\n var serviceClass = beanClass+'Service';\n var serviceVarName= beanVarName+'Service';\n \n}}package {{=pkgName}}.mapper;\n$blankline\n\nimport com.baomidou.mybatisplus.core.conditions.Wrapper;\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.core.toolkit.Constants;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Param;\nimport {{=pkgName}}.entity.{{=beanClass}};\n$blankline\n\n /**\n * {{=it.entity.defName}};({{=it.entity.defKey}})表数据库访问层\n * @author : http://www.chiner.pro\n * @date : {{=fullYear}}-{{=month}}-{{=days}}\n */\n@Mapper\npublic interface {{=beanClass}}Mapper extends BaseMapper<{{=beanClass}}>{\n /** \n * 分页查询指定行数据\n *\n * @param page 分页参数\n * @param wrapper 动态查询条件\n * @return 分页对象列表\n */\n IPage<{{=beanClass}}> selectByPage(IPage<{{=beanClass}}> page , @Param(Constants.WRAPPER) Wrapper<{{=beanClass}}> wrapper);\n}", + "Mapper.xml": "{{ var today=new Date();\n var fullYear=today.getFullYear();\n var month=today.getMonth() + 1;\n var days=today.getDate();\n \n var pkVarName = \"undefinedId\";\n var pkDataType = \"String\";\n var pkField = \"UNDEFINED_ID\";\n it.entity.fields.forEach(function(field){\n if(field.primaryKey){\n pkField = field.defKey;\n pkVarName = it.func.camel(field.defKey,false);\n pkDataType = field[\"type\"];\n return;\n }\n });\n \n var pkgName = it.entity.env.base.nameSpace;\n var beanClass = it.entity.env.base.codeRoot;\n var beanVarName = beanClass.charAt(0).toLowerCase()+beanClass.slice(1);\n var serviceClass = beanClass+'Service';\n var serviceVarName= beanVarName+'Service';\n \n}}\n\n$blankline\n\n\n \n\n\n", + "Entity": "{{ var today=new Date();\n var fullYear=today.getFullYear();\n var month=today.getMonth() + 1;\n var days=today.getDate();\n \n var pkVarName = \"undefinedId\";\n var pkDataType = \"String\";\n it.entity.fields.forEach(function(field){\n if(field.primaryKey){\n pkVarName = it.func.camel(field.defKey,false);\n pkDataType = field[\"type\"];\n return;\n }\n });\n \n var pkgName = it.entity.env.base.nameSpace;\n var beanClass = it.entity.env.base.codeRoot;\n var beanVarName = beanClass.charAt(0).toLowerCase()+beanClass.slice(1);\n var serviceClass = beanClass+'Service';\n var serviceVarName= beanVarName+'Service';\n \n}}package {{=pkgName}}.entity;\n$blankline\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport java.io.Serializable;\nimport java.util.Date;\n$blankline\n\n /**\n * {{=it.entity.defName}};{{=it.entity.comment}}\n * @author : http://www.chiner.pro\n * @date : {{=fullYear}}-{{=month}}-{{=days}}\n */\n@ApiModel(value = \"{{=it.entity.defName}}\",description = \"{{=it.entity.comment}}\")\n@TableName(\"{{=it.entity.defKey}}\")\npublic class {{=beanClass}} implements Serializable,Cloneable{\n{{~it.entity.fields:field:index}}\n /** {{=it.func.join(field.defName,field.comment,';')}} */\n @ApiModelProperty(name = \"{{=field.defName}}\",notes = \"{{=field.comment}}\")\n {{? field.primaryKey }}\n @TableId\n {{?}}\n private {{=field.type}} {{=it.func.camel(field.defKey,false)}} ;\n{{~}}\n$blankline\n\n{{~it.entity.fields:field:index}}\n /** {{=it.func.join(field.defName,field.comment,';')}} */\n public {{=field.type}} get{{=it.func.camel(field.defKey,true)}}(){\n return this.{{=it.func.camel(field.defKey,false)}};\n }\n /** {{=it.func.join(field.defName,field.comment,';')}} */\n public void set{{=it.func.camel(field.defKey,true)}}({{=field.type}} {{= it.func.camel(field.defKey,false) }}){\n this.{{=it.func.camel(field.defKey,false)}}={{=it.func.camel(field.defKey,false)}};\n }\n{{~}}\n}" + }, + { + "applyFor": "29D1CE08-4C35-4D2D-AAA9-23D93305B52E", + "type": "dbDDL", + "createTable": "DROP TABLE IF EXISTS {{=it.entity.defKey}};\nCREATE TABLE {{=it.entity.defKey}}(\n{{ pkList = [] ; }}\n{{~it.entity.fields:field:index}}\n {{? field.primaryKey }}{{ pkList.push(field.defKey) }}{{?}}\n `{{=field.defKey}}` {{=field.type}}{{?field.len>0}}{{='('}}{{=field.len}}{{?field.scale>0}}{{=','}}{{=field.scale}}{{?}}{{=')'}}{{?}} {{= field.notNull ? 'NOT NULL' : '' }} {{= field.autoIncrement ? 'AUTO_INCREMENT' : '' }} {{= field.defaultValue ? it.func.join('DEFAULT',field.defaultValue,' ') : '' }} COMMENT '{{=it.func.join(field.defName,field.comment,';')}}' {{= index < it.entity.fields.length-1 ? ',' : ( pkList.length>0 ? ',' :'' ) }}\n{{~}}\n{{? pkList.length >0 }}\n PRIMARY KEY ({{~pkList:pkName:i}}{{= pkName }}{{= i'+(after.defKey||'NULL'));\n }\n if(before.defName !== after.defName){\n ret.push('显示名称:'+(before.defName||'NULL')+'->'+(after.defName||'NULL'));\n }\n if(before.comment !== after.comment){\n ret.push('说明:'+(before.comment||'NULL')+'->'+(after.comment||'NULL'));\n }\n if(ret.length>0){\n return ' 基本信息:\\n\\t'+ret.join('\\n\\t');\n }\n return '';\n };\n \n function buildAddedDesc(entity){\n let ret = [];\n let fieldAdded = entity.data.fieldAdded||[];\n \n for (let field of fieldAdded) { \n let row = [];\n row.push(field.defKey+'['+field.defName+']');\n ret.push(row.join(\"\"))\n }\n return ret;\n };\n \n function buildRemovedDesc(entity){\n let ret = [];\n let fieldRemoved = entity.data.fieldRemoved||[];\n \n for (let field of fieldRemoved) { \n let row = [];\n row.push(field.defKey+'['+field.defName+']');\n ret.push(row.join(\"\"))\n }\n return ret;\n };\n \n function buildModifiedDesc(entity){\n let ret = [];\n let fieldModified = entity.data.fieldModified||[];\n \n for (let field1 of fieldModified) { \n let row = [];\n let field = field1.before;\n row.push(field.defKey+'['+field.defName+']');\n ret.push(row.join(\"\"))\n }\n return ret;\n };\n}}\n\n\n{{? createEntities && createEntities.length > 0}}\n/* --------------- 创建表 --------------- */\n{{~ createEntities:entity}}\n{{=entity.data.defKey}}[{{=entity.data.defName}}]\n{{~}}\n{{?}}\n\n\n{{? dropEntities && dropEntities.length > 0}}\n/* --------------- 删除表 --------------- */\n{{~ dropEntities:entity}}\n{{=entity.data.defKey}}[{{=entity.data.defName}}]\n{{~}}\n{{?}}\n\n{{? modifyEntities && modifyEntities.length > 0}}\n/* --------------- 修改表 --------------- */\n{{~ modifyEntities:entity}}\n{{=entity.data.baseInfo.defKey}}[{{=entity.data.baseInfo.defName}}]{{let changeText=baseChanged(entity.data.baseChanged);}}\n{{=baseChanged(entity.data.baseChanged)}}\n {{? entity.data.fieldModified && entity.data.fieldModified.length > 0}}\n 修改字段:\n {{='\\t'}}{{=buildModifiedDesc(entity).join('\\n\\t')}}{{?}}{{\n /*计算是否调整了属性*/\n let propAdded = entity.data.propAdded || [];\n let propRemoved = entity.data.propRemoved || [];\n let propModified = entity.data.propModified || [];\n let changed = propAdded.length>0 || propRemoved.length>0 || propModified.length>0;\n /*计算关联是否调整*/\n let refEntityAdd = entity.data.refEntityAdd || [];\n let refEntityRemoved = entity.data.refEntityRemoved || [];\n let relaArray = [];\n for (let rela of refEntityAdd) {\n relaArray.push('建立关联:'+rela.defKey+'['+rela.defName+']');\n }\n for (let rela of refEntityRemoved) {\n relaArray.push('解除关联:'+rela.defKey+'['+rela.defName+']');\n }\n /*索引是否修改过*/\n let indexChanged = entity.data.indexChanged;\n }}{{=indexChanged?'\\n\\t更改了索引':''}}{{=changed?'\\n\\t更改了属性':''}}{{=relaArray.length>0?('\\n\\t'+relaArray.join('\\n\\t')):''}}\n{{? entity.data.fieldAdded && entity.data.fieldAdded.length > 0}}\n 添加字段:\n{{='\\t'}}{{=buildAddedDesc(entity).join('\\n\\t')}}\n{{?}}{{? entity.data.fieldRemoved && entity.data.fieldRemoved.length > 0}}\n 删除字段:\n{{='\\t'}}{{=buildRemovedDesc(entity).join('\\n\\t')}}\n{{?}}\n{{~}}\n{{?}}\n", + "update": "{{\n let createEntities = it.changes.filter(function(row){return (row.opt==='add'&&row['type']==='entity');});\n let dropEntities = it.changes.filter(function(row){return (row.opt==='delete'&&row['type']==='entity');});\n let modifyEntities = it.changes.filter(function(row){return (row.opt==='update'&&row['type']==='entity');});\n \n function baseChangedDDL(beforeAfter){\n if(beforeAfter == null){\n return '';\n }\n let ret = [];\n let before = beforeAfter.before || {\"defKey\":\"\",\"defName\":\"\",\"comment\":\"\"};\n let after = beforeAfter.after || {\"defKey\":\"\",\"defName\":\"\",\"comment\":\"\"};\n if(before.defKey !== after.defKey){\n ret.push('ALTER TABLE '+before.defKey+' RENAME TO '+after.defKey);\n }\n let commentText = '';\n let commentChanged = false;\n if(before.defName !== after.defName){\n commentText = after.defName;\n commentChanged = true;\n }\n if(before.comment !== after.comment){\n commentChanged = true;\n if(commentText){\n commentText = (commentText+ ';'+after.comment)\n }else{\n commentText = after.comment\n }\n }\n if(commentChanged){\n ret.push('ALTER TABLE '+after.defKey+' COMMENT \\''+commentText+'\\'');\n }\n let baseText = '-- 基本信息:\\n';\n return baseText+ret.join(';\\n')+';';\n };\n \n function buildAddedDDL(entity){\n let ret = [];\n let fieldAdded = entity.data.fieldAdded||[];\n if(fieldAdded.length == 0){\n return '';\n }\n \n let firstDDL = 'ALTER TABLE '+entity.data.baseInfo.defKey;\n for (let field of fieldAdded) { \n let ddlItem = 'ADD COLUMN `'+field.defKey+'` '+field.dbType;\n /*处理数据类型长度*/\n if(field.len>0){\n ddlItem += ('('+field.len);\n if(parseInt(field.scale)>0){\n ddlItem += (','+field.scale);\n }\n ddlItem += ')';\n }\n if(field.notNull){\n ddlItem += ' NOT NULL';\n }\n if(field.autoIncrement){\n ddlItem += ' AUTO_INCREMENT';\n }\n if(field.defaultValue){\n ddlItem += (' DEFAULT ' + field.defaultValue);\n }\n ddlItem += (' COMMENT \\''+field.defName+';'+field.comment+'\\'');\n \n if(field.index>0 && field.afterFieldKey){\n ddlItem += (' AFTER '+field.afterFieldKey);\n }\n ret.push(ddlItem);\n }\n return firstDDL+'\\n'+ret.join(',\\n');\n };\n \n function buildRemovedDDL(entity){\n let ret = [];\n let fieldRemoved = entity.data.fieldRemoved||[];\n if(fieldRemoved.length == 0){\n return '';\n }\n \n let firstDDL = 'ALTER TABLE '+entity.data.baseInfo.defKey;\n for (let field of fieldRemoved) { \n ret.push('DROP '+field.defKey);\n }\n return firstDDL+'\\n'+ret.join(',\\n');\n };\n \n function buildModifiedDDL(entity){\n let ret = [];\n let fieldModified = entity.data.fieldModified||[];\n \n let firstDDL = 'ALTER TABLE '+entity.data.baseInfo.defKey;\n for (let field of fieldModified) { \n let changeDDL = '';\n let before = field.before || {};\n let after = field.after || {};\n if(before.defKey === after.defKey){\n changeDDL += (' MODIFY COLUMN `'+after.defKey+'`');\n }else{\n changeDDL += (' CHANGE COLUMN `'+before.defKey+'` `'+after.defKey+'`');\n }\n changeDDL += (' '+after.dbType);\n if(after.len>0){\n changeDDL += ('('+after.len);\n if(parseInt(after.scale)>0){\n changeDDL += (','+after.scale);\n }\n changeDDL += ')';\n }\n if(after.notNull){\n changeDDL += ' NOT NULL';\n }\n let defaultValue = '';\n if(after.defaultValue != null && after.defaultValue.length>0){\n defaultValue = (after.defaultValue);\n }else{\n defaultValue = 'NULL';\n }\n if(defaultValue != 'NULL'){\n changeDDL += (' DEFAULT ' + defaultValue);\n }\n\n let comment = after.defName;\n if(after.comment){\n comment = comment + ';' + (after.comment||'');\n }\n if(comment){\n changeDDL += (' COMMENT \\''+comment+'\\';');\n }\n \n ret.push(firstDDL+' '+changeDDL);\n }\n return ret;\n };\n}}\n{{? createEntities && createEntities.length > 0}}\n/* --------------- 创建表 --------------- */\n{{~ createEntities:entity}}\n{{=it.func.createDDL(entity.data,entity['type'])}}\n{{~}}\n{{?}}\n\n\n{{? dropEntities && dropEntities.length > 0}}\n/* --------------- 删除表 --------------- */\n{{~ dropEntities:entity}}\n{{=it.func.dropDDL(entity.data,entity['type'])}}\n{{~}}\n{{?}}\n\n\n{{? modifyEntities && modifyEntities.length > 0}}\n{{~ modifyEntities:entity}}\n/* --------------- 修改表 --------------- */\n-- 修改表:{{=entity.data.baseInfo.defKey}}[{{=entity.data.baseInfo.defName}}]\n{{=baseChangedDDL(entity.data.baseChanged)}}\n{{? entity.data.fieldModified && entity.data.fieldModified.length > 0}}\n-- 修改字段:\n{{=buildModifiedDDL(entity).join('\\n')}}\n{{?}}{{\n/*索引是否修改过*/\nlet indexChanged = entity.data.indexChanged;\n}}\n{{? indexChanged }}\n{{=it.func.indexRebuildDDL(entity.data.baseInfo,entity.data.newIndexes,entity.data.fullFields,entity['type'])}}\n{{?}}\n\n{{? entity.data.fieldAdded && entity.data.fieldAdded.length > 0}}\n-- 添加字段:\n{{=buildAddedDDL(entity)}};\n{{?}}\n\n{{? entity.data.fieldRemoved && entity.data.fieldRemoved.length > 0}}\n-- 删除字段:\n{{=buildRemovedDDL(entity)}};\n{{?}}\n{{~}}\n{{?}}" + }, + { + "applyFor": "A4E23CB7-BB01-4BD1-9F71-F73F3E15A542", + "type": "dbDDL", + "createTable": "CREATE TABLE {{=it.entity.defKey}}(\n{{ pkList = [] ; }}\n{{~it.entity.fields:field:index}}\n {{? field.primaryKey }}{{ pkList.push(field.defKey) }}{{?}}\n {{=field.defKey}} {{=field.type}}{{?field.len>0}}{{='('}}{{=field.len}}{{?field.scale>0}}{{=','}}{{=field.scale}}{{?}}{{=')'}}{{?}}{{= field.defaultValue ? it.func.join(' DEFAULT ',field.defaultValue,' ') : '' }}{{= field.notNull ? ' NOT NULL' : '' }}{{= field.autoIncrement ? '' : '' }}{{= index < it.entity.fields.length-1 ? ',' : ( pkList.length>0 ? ',' :'' ) }}\n{{~}}\n{{? pkList.length >0 }}\n PRIMARY KEY ({{~pkList:pkName:i}}{{= pkName }}{{= i'+(after.defKey||'NULL'));\n }\n if(before.defName !== after.defName){\n ret.push('显示名称:'+(before.defName||'NULL')+'->'+(after.defName||'NULL'));\n }\n if(before.comment !== after.comment){\n ret.push('说明:'+(before.comment||'NULL')+'->'+(after.comment||'NULL'));\n }\n if(ret.length>0){\n return ' 基本信息:\\n\\t'+ret.join('\\n\\t');\n }\n return '';\n };\n \n function buildAddedDesc(entity){\n let ret = [];\n let fieldAdded = entity.data.fieldAdded||[];\n \n for (let field of fieldAdded) { \n let row = [];\n row.push(field.defKey+'['+field.defName+']');\n ret.push(row.join(\"\"))\n }\n return ret;\n };\n \n function buildRemovedDesc(entity){\n let ret = [];\n let fieldRemoved = entity.data.fieldRemoved||[];\n \n for (let field of fieldRemoved) { \n let row = [];\n row.push(field.defKey+'['+field.defName+']');\n ret.push(row.join(\"\"))\n }\n return ret;\n };\n \n function buildModifiedDesc(entity){\n let ret = [];\n let fieldModified = entity.data.fieldModified||[];\n \n for (let field1 of fieldModified) { \n let row = [];\n let field = field1.before;\n row.push(field.defKey+'['+field.defName+']');\n ret.push(row.join(\"\"))\n }\n return ret;\n };\n}}\n{{? createEntities && createEntities.length > 0}}\n/* -------------------------------------------------- */\n创建表:\n{{~ createEntities:entity}}\n {{=entity.data.defKey}}[{{=entity.data.defName}}]\n{{~}}\n{{?}}\n\n\n{{? dropEntities && dropEntities.length > 0}}\n/* -------------------------------------------------- */\n删除表:\n{{~ dropEntities:entity}}\n {{=entity.data.defKey}}[{{=entity.data.defName}}]\n{{~}}\n{{?}}\n\n\n{{? modifyEntities && modifyEntities.length > 0}}\n{{~ modifyEntities:entity}}\n/* -------------------------------------------------- */\n修改表:{{=entity.data.baseInfo.defKey}}[{{=entity.data.baseInfo.defName}}]{{let changeText=baseChanged(entity.data.baseChanged);}}\n{{=baseChanged(entity.data.baseChanged)}}\n {{? entity.data.fieldAdded && entity.data.fieldAdded.length > 0}}\n 添加字段:\n {{='\\t'}}{{=buildAddedDesc(entity).join('\\n\\t')}}\n {{?}}{{? entity.data.fieldRemoved && entity.data.fieldRemoved.length > 0}}\n 删除字段:\n {{='\\t'}}{{=buildRemovedDesc(entity).join('\\n\\t')}}\n {{?}}{{? entity.data.fieldModified && entity.data.fieldModified.length > 0}}\n 修改字段:\n {{='\\t'}}{{=buildModifiedDesc(entity).join('\\n\\t')}}\n {{?}}{{\n /*计算是否调整了属性*/\n let propAdded = entity.data.propAdded || [];\n let propRemoved = entity.data.propRemoved || [];\n let propModified = entity.data.propModified || [];\n let changed = propAdded.length>0 || propRemoved.length>0 || propModified.length>0;\n /*计算关联是否调整*/\n let refEntityAdd = entity.data.refEntityAdd || [];\n let refEntityRemoved = entity.data.refEntityRemoved || [];\n let relaArray = [];\n for (let rela of refEntityAdd) {\n relaArray.push('\\n\\t建立关联:'+rela.defKey+'['+rela.defName+']');\n }\n for (let rela of refEntityRemoved) {\n relaArray.push('\\n\\t解除关联:'+rela.defKey+'['+rela.defName+']');\n }\n /*索引是否修改过*/\n let indexChanged = entity.data.indexChanged;\n }}\n{{=indexChanged?'\\n\\t更改了索引':''}}\n{{=changed?'\\n\\t更改了属性':''}}\n{{=relaArray.length>0?relaArray.join(''):''}}\n{{~}}\n{{?}}", + "update": "{{\n let createEntities = it.changes.filter(function(row){return (row.opt==='add'&&row['type']==='entity');});\n let dropEntities = it.changes.filter(function(row){return (row.opt==='delete'&&row['type']==='entity');});\n let modifyEntities = it.changes.filter(function(row){return (row.opt==='update'&&row['type']==='entity');});\n \n function baseChangedDDL(beforeAfter){\n if(beforeAfter == null){\n return '';\n }\n let ret = [];\n let before = beforeAfter.before || {\"defKey\":\"\",\"defName\":\"\",\"comment\":\"\"};\n let after = beforeAfter.after || {\"defKey\":\"\",\"defName\":\"\",\"comment\":\"\"};\n if(before.defKey !== after.defKey){\n ret.push(`ALTER TABLE ${before.defKey} RENAME TO ${after.defKey}`);\n }\n let commentText = '';\n let commentChanged = false;\n if(before.defName !== after.defName){\n commentText = after.defName;\n commentChanged = true;\n }\n if(before.comment !== after.comment){\n commentChanged = true;\n if(commentText){\n commentText = (commentText+ ';'+after.comment)\n }else{\n commentText = after.comment\n }\n }\n if(commentChanged){\n let myText = `COMMENT ON TABLE ${after.defKey} IS '${commentText}'`;\n ret.push(myText);\n }\n let baseText = '-- 基本信息:\\n';\n return baseText+ret.join(';\\n')+';';\n };\n \n function buildAddedDDL(entity){\n let ret = [];\n let fieldAdded = entity.data.fieldAdded||[];\n if(fieldAdded.length == 0){\n return '';\n }\n \n let firstDDL = `ALTER TABLE ${entity.data.baseInfo.defKey}`;\n for (let field of fieldAdded) { \n let ddlItem = `ADD (${field.defKey} ${field.dbType}`;\n /*处理数据类型长度*/\n if(field.len>0){\n ddlItem += ('('+field.len);\n if(parseInt(field.scale)>0){\n ddlItem += (','+field.scale);\n }\n ddlItem += ')';\n }\n let defaultValue = field.defaultValue;\n defaultValue = (defaultValue==null)?\"\":(\"\"+defaultValue);\n if(defaultValue.length>0){\n ddlItem += (' DEFAULT ' + defaultValue);\n }\n if(field.notNull){\n ddlItem += ' NOT NULL';\n }\n ddlItem += ')';\n ret.push(`${firstDDL} ${ddlItem}`);\n \n /*处理字段注释*/\n let fieldComments = [];\n if(field.defName != null &&field.defName.length>0){\n fieldComments.push(field.defName);\n }\n if(field.comment != null &&field.comment.length>0){\n fieldComments.push(field.comment);\n }\n let commentText = fieldComments.join(';');\n if(commentText != null && commentText.length > 0){\n let commentDDL = `COMMENT ON COLUMN ${entity.data.baseInfo.defKey}.${field.defKey} IS '${commentText}'`;\n ret.push(commentDDL);\n }\n }\n return '\\n'+ret.join(';\\n');\n };\n \n function buildRemovedDDL(entity){\n let ret = [];\n let fieldRemoved = entity.data.fieldRemoved||[];\n if(fieldRemoved.length == 0){\n return '';\n }\n \n let firstDDL = `ALTER TABLE ${entity.data.baseInfo.defKey}`;\n for (let field of fieldRemoved) { \n ret.push(`${firstDDL} DROP COLUMN ${field.defKey}`);\n }\n return '\\n'+ret.join(';\\n');\n };\n \n function buildModifiedDDL(entity){\n let ret = [];\n let fieldModified = entity.data.fieldModified||[];\n \n let firstDDL = `ALTER TABLE ${entity.data.baseInfo.defKey}`;\n for (let field of fieldModified) { \n let changeDDL = '';\n let before = field.before || {};\n let after = field.after || {};\n if(before.defKey !== after.defKey){\n let renameText = `ALTER TABLE ${entity.data.baseInfo.defKey} RENAME COLUMN ${before.defKey} TO ${after.defKey};`;\n ret.push(renameText);\n }\n /*如果没有变化,则不生成变更语句*/\n if(before.dbType === after.dbType \n && before['len'] === after['len'] \n && before.scale === after.scale\n && before.primaryKey === after.primaryKey\n && before.notNull === after.notNull\n && before.autoIncrement === after.autoIncrement\n && before.defaultValue === after.defaultValue){\n continue;\n }\n changeDDL += ('MODIFY ('+after.defKey+'');\n changeDDL += (' '+after.dbType);\n if(after.len>0){\n changeDDL += ('('+after.len);\n if(parseInt(after.scale)>0){\n changeDDL += (','+after.scale);\n }\n changeDDL += ')';\n }\n let defaultValue = after.defaultValue;\n defaultValue = (defaultValue==null)?\"\":(\"\"+defaultValue);\n if(defaultValue.length>0){\n changeDDL += (' DEFAULT ' + defaultValue);\n }\n \n if(after.notNull){\n changeDDL += ' NOT NULL';\n }\n changeDDL += ')';\n ret.push(`${firstDDL} ${changeDDL};`);\n }\n return ret;\n };\n}}\n{{? createEntities && createEntities.length > 0}}\n/* --------------- 创建表 --------------- */\n{{~ createEntities:entity}}\n{{=it.func.createDDL(entity.data,entity['type'])}}\n{{~}}\n{{?}}\n\n\n{{? dropEntities && dropEntities.length > 0}}\n/* --------------- 删除表 --------------- */\n{{~ dropEntities:entity}}\n{{=it.func.dropDDL(entity.data,entity['type'])}}\n{{~}}\n{{?}}\n\n\n{{? modifyEntities && modifyEntities.length > 0}}\n{{~ modifyEntities:entity}}\n/* --------------- 修改表 --------------- */\n-- 修改表:{{=entity.data.baseInfo.defKey}}[{{=entity.data.baseInfo.defName}}]\n{{=baseChangedDDL(entity.data.baseChanged)}}\n{{? entity.data.fieldModified && entity.data.fieldModified.length > 0}}\n-- 修改字段:\n{{=buildModifiedDDL(entity).join('\\n')}}\n{{?}}{{\n/*索引是否修改过*/\nlet indexChanged = entity.data.indexChanged;\n}}\n{{? indexChanged }}\n{{=it.func.indexRebuildDDL(entity.data.baseInfo,entity.data.newIndexes,entity.data.fullFields,entity['type'])}}\n{{?}}\n\n{{? entity.data.fieldAdded && entity.data.fieldAdded.length > 0}}\n-- 添加字段:\n{{=buildAddedDDL(entity)}};\n{{?}}\n\n{{? entity.data.fieldRemoved && entity.data.fieldRemoved.length > 0}}\n-- 删除字段:\n{{=buildRemovedDDL(entity)}};\n{{?}}\n{{~}}\n{{?}}" + }, + { + "applyFor": "BFC87171-C74F-494A-B7C2-76B9C55FACC9", + "type": "dbDDL", + "createTable": "IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[{{=it.entity.defKey}}]') AND type in (N'U')) DROP TABLE [dbo].[{{=it.entity.defKey}}];\n\nCREATE TABLE [dbo].[{{=it.entity.defKey}}](\n{{ pkList = [] ; }}\n{{~it.entity.fields:field:index}}\n {{? field.primaryKey }}{{ pkList.push(field.defKey) }}{{?}}\n {{=field.defKey}} {{=field.type}}{{?field.len>0}}{{='('}}{{=field.len}}{{?field.scale>0}}{{=','}}{{=field.scale}}{{?}}{{=')'}}{{?}}{{= field.notNull ? ' NOT NULL' : '' }}{{= field.autoIncrement ? ' IDENTITY(1,1)' : '' }}{{= field.defaultValue ? it.func.join(' DEFAULT ',field.defaultValue,' ') : '' }}{{= index < it.entity.fields.length-1 ? ',' : ( pkList.length>0 ? ',' :'' ) }}\n{{~}}\n{{? pkList.length >0 }}\n PRIMARY KEY ({{~pkList:pkName:i}}{{= pkName }}{{= i'+(after.defKey||'NULL'));\n }\n if(before.defName !== after.defName){\n ret.push('显示名称:'+(before.defName||'NULL')+'->'+(after.defName||'NULL'));\n }\n if(before.comment !== after.comment){\n ret.push('说明:'+(before.comment||'NULL')+'->'+(after.comment||'NULL'));\n }\n if(ret.length>0){\n return ' 基本信息:\\n\\t'+ret.join('\\n\\t');\n }\n return '';\n };\n \n function buildAddedDesc(entity){\n let ret = [];\n let fieldAdded = entity.data.fieldAdded||[];\n \n for (let field of fieldAdded) { \n let row = [];\n row.push(field.defKey+'['+field.defName+']');\n ret.push(row.join(\"\"))\n }\n return ret;\n };\n \n function buildRemovedDesc(entity){\n let ret = [];\n let fieldRemoved = entity.data.fieldRemoved||[];\n \n for (let field of fieldRemoved) { \n let row = [];\n row.push(field.defKey+'['+field.defName+']');\n ret.push(row.join(\"\"))\n }\n return ret;\n };\n \n function buildModifiedDesc(entity){\n let ret = [];\n let fieldModified = entity.data.fieldModified||[];\n \n for (let field1 of fieldModified) { \n let row = [];\n let field = field1.before;\n row.push(field.defKey+'['+field.defName+']');\n ret.push(row.join(\"\"))\n }\n return ret;\n };\n}}\n\n\n{{? createEntities && createEntities.length > 0}}\n/* --------------- 创建表 --------------- */\n{{~ createEntities:entity}}\n{{=entity.data.defKey}}[{{=entity.data.defName}}]\n{{~}}\n{{?}}\n\n\n{{? dropEntities && dropEntities.length > 0}}\n/* --------------- 删除表 --------------- */\n{{~ dropEntities:entity}}\n{{=entity.data.defKey}}[{{=entity.data.defName}}]\n{{~}}\n{{?}}\n\n{{? modifyEntities && modifyEntities.length > 0}}\n/* --------------- 修改表 --------------- */\n{{~ modifyEntities:entity}}\n{{=entity.data.baseInfo.defKey}}[{{=entity.data.baseInfo.defName}}]{{let changeText=baseChanged(entity.data.baseChanged);}}\n{{=baseChanged(entity.data.baseChanged)}}\n {{? entity.data.fieldModified && entity.data.fieldModified.length > 0}}\n 修改字段:\n {{='\\t'}}{{=buildModifiedDesc(entity).join('\\n\\t')}}{{?}}{{\n /*计算是否调整了属性*/\n let propAdded = entity.data.propAdded || [];\n let propRemoved = entity.data.propRemoved || [];\n let propModified = entity.data.propModified || [];\n let changed = propAdded.length>0 || propRemoved.length>0 || propModified.length>0;\n /*计算关联是否调整*/\n let refEntityAdd = entity.data.refEntityAdd || [];\n let refEntityRemoved = entity.data.refEntityRemoved || [];\n let relaArray = [];\n for (let rela of refEntityAdd) {\n relaArray.push('建立关联:'+rela.defKey+'['+rela.defName+']');\n }\n for (let rela of refEntityRemoved) {\n relaArray.push('解除关联:'+rela.defKey+'['+rela.defName+']');\n }\n /*索引是否修改过*/\n let indexChanged = entity.data.indexChanged;\n }}{{=indexChanged?'\\n\\t更改了索引':''}}{{=changed?'\\n\\t更改了属性':''}}{{=relaArray.length>0?('\\n\\t'+relaArray.join('\\n\\t')):''}}\n{{? entity.data.fieldAdded && entity.data.fieldAdded.length > 0}}\n 添加字段:\n{{='\\t'}}{{=buildAddedDesc(entity).join('\\n\\t')}}\n{{?}}{{? entity.data.fieldRemoved && entity.data.fieldRemoved.length > 0}}\n 删除字段:\n{{='\\t'}}{{=buildRemovedDesc(entity).join('\\n\\t')}}\n{{?}}\n{{~}}\n{{?}}", + "update": "{{\n let createEntities = it.changes.filter(function(row){return (row.opt==='add'&&row['type']==='entity');});\n let dropEntities = it.changes.filter(function(row){return (row.opt==='delete'&&row['type']==='entity');});\n let modifyEntities = it.changes.filter(function(row){return (row.opt==='update'&&row['type']==='entity');});\n \n function baseChangedDDL(beforeAfter){\n if(beforeAfter == null){\n return '';\n }\n let ret = [];\n let before = beforeAfter.before || {\"defKey\":\"\",\"defName\":\"\",\"comment\":\"\"};\n let after = beforeAfter.after || {\"defKey\":\"\",\"defName\":\"\",\"comment\":\"\"};\n if(before.defKey !== after.defKey){\n ret.push(`EXEC sp_rename '${before.defKey}','${after.defKey}'`);\n }\n let commentText = '';\n let commentChanged = false;\n if(before.defName !== after.defName){\n commentText = after.defName;\n commentChanged = true;\n }\n if(before.comment !== after.comment){\n commentChanged = true;\n if(commentText){\n commentText = (commentText+ ';'+after.comment)\n }else{\n commentText = after.comment\n }\n }\n if(commentChanged){\n let myText = `IF ((SELECT COUNT(*) FROM ::fn_listextendedproperty('MS_Description','SCHEMA', 'dbo','TABLE', '${after.defKey}', NULL, NULL)) > 0)\n \\n\\tEXEC sp_updateextendedproperty 'MS_Description', '${commentText}','SCHEMA', 'dbo','TABLE', '${after.defKey}'\n \\nELSE\n \\n\\tEXEC sp_addextendedproperty 'MS_Description', '${commentText}', 'SCHEMA', 'dbo','TABLE', '${after.defKey}'\n `;\n ret.push(myText);\n /*ret.push('ALTER TABLE '+after.defKey+' COMMENT \\''+commentText+'\\'');*/\n }\n let baseText = '-- 基本信息:\\n';\n return baseText+ret.join(';\\n')+';';\n };\n \n function buildAddedDDL(entity){\n let ret = [];\n let fieldAdded = entity.data.fieldAdded||[];\n if(fieldAdded.length == 0){\n return '';\n }\n \n let firstDDL = `ALTER TABLE [dbo].[${entity.data.baseInfo.defKey}]`;\n for (let field of fieldAdded) { \n let ddlItem = `ADD [${field.defKey}] ${field.dbType}`;\n /*处理数据类型长度*/\n if(field.len>0){\n ddlItem += ('('+field.len);\n if(parseInt(field.scale)>0){\n ddlItem += (','+field.scale);\n }\n ddlItem += ')';\n }\n let defaultValue = field.defaultValue;\n defaultValue = (defaultValue==null)?\"\":(\"\"+defaultValue);\n if(defaultValue.length>0){\n ddlItem += (' DEFAULT ' + defaultValue);\n }\n if(field.notNull){\n ddlItem += ' NOT NULL';\n }\n ret.push(`${firstDDL} ${ddlItem}`);\n \n /*处理字段注释*/\n let fieldComments = [];\n if(field.defName != null &&field.defName.length>0){\n fieldComments.push(field.defName);\n }\n if(field.comment != null &&field.comment.length>0){\n fieldComments.push(field.comment);\n }\n let commentText = fieldComments.join(';');\n if(commentText != null && commentText.length > 0){\n let commentDDL = `EXEC sp_addextendedproperty 'MS_Description', N'${commentText}','SCHEMA', N'dbo','TABLE', N'${entity.data.baseInfo.defKey}','COLUMN', N'${field.defKey}'`;\n ret.push(commentDDL);\n }\n }\n return '\\n'+ret.join(';\\n');\n };\n \n function buildRemovedDDL(entity){\n let ret = [];\n let fieldRemoved = entity.data.fieldRemoved||[];\n if(fieldRemoved.length == 0){\n return '';\n }\n \n let firstDDL = `ALTER TABLE [dbo].[${entity.data.baseInfo.defKey}]`;\n for (let field of fieldRemoved) { \n ret.push(`${firstDDL} DROP COLUMN [${field.defKey}]`);\n }\n return '\\n'+ret.join(';\\n');\n };\n \n function buildModifiedDDL(entity){\n let ret = [];\n let fieldModified = entity.data.fieldModified||[];\n \n let firstDDL = `ALTER TABLE [dbo].[${entity.data.baseInfo.defKey}]`;\n for (let field of fieldModified) { \n let changeDDL = '';\n let before = field.before || {};\n let after = field.after || {};\n if(before.defKey === after.defKey){\n changeDDL += (' ALTER COLUMN ['+after.defKey+']');\n }else{\n let renameText = `EXEC sp_rename '[dbo].[${entity.data.baseInfo.defKey}].[${before.defKey}]','${after.defKey}','COLUMN';`;\n ret.push(renameText);\n continue;\n }\n changeDDL += (' '+after.dbType);\n if(after.len>0){\n changeDDL += ('('+after.len);\n if(parseInt(after.scale)>0){\n changeDDL += (','+after.scale);\n }\n changeDDL += ')';\n }\n let defaultValue = after.defaultValue;\n defaultValue = (defaultValue==null)?\"\":(\"\"+defaultValue);\n if(defaultValue.length>0){\n changeDDL += (' DEFAULT ' + defaultValue);\n }\n \n if(after.notNull){\n changeDDL += ' NOT NULL';\n }\n ret.push(`${firstDDL} ${changeDDL};`);\n }\n return ret;\n };\n}}\n{{? createEntities && createEntities.length > 0}}\n/* --------------- 创建表 --------------- */\n{{~ createEntities:entity}}\n{{=it.func.createDDL(entity.data,entity['type'])}}\n{{~}}\n{{?}}\n\n\n{{? dropEntities && dropEntities.length > 0}}\n/* --------------- 删除表 --------------- */\n{{~ dropEntities:entity}}\n{{=it.func.dropDDL(entity.data,entity['type'])}}\n{{~}}\n{{?}}\n\n\n{{? modifyEntities && modifyEntities.length > 0}}\n{{~ modifyEntities:entity}}\n/* --------------- 修改表 --------------- */\n-- 修改表:{{=entity.data.baseInfo.defKey}}[{{=entity.data.baseInfo.defName}}]\n{{=baseChangedDDL(entity.data.baseChanged)}}\n{{? entity.data.fieldModified && entity.data.fieldModified.length > 0}}\n-- 修改字段:\n{{=buildModifiedDDL(entity).join('\\n')}}\n{{?}}{{\n/*索引是否修改过*/\nlet indexChanged = entity.data.indexChanged;\n}}\n{{? indexChanged }}\n{{=it.func.indexRebuildDDL(entity.data.baseInfo,entity.data.newIndexes,entity.data.fullFields,entity['type'])}}\n{{?}}\n\n{{? entity.data.fieldAdded && entity.data.fieldAdded.length > 0}}\n-- 添加字段:\n{{=buildAddedDDL(entity)}};\n{{?}}\n\n{{? entity.data.fieldRemoved && entity.data.fieldRemoved.length > 0}}\n-- 删除字段:\n{{=buildRemovedDDL(entity)}};\n{{?}}\n{{~}}\n{{?}}" + }, + { + "applyFor": "DFBEC1DD-AA84-456E-BBF3-C95DD0DB2022", + "type": "dbDDL", + "createTable": "DROP TABLE IF EXISTS {{=it.entity.defKey}};\nCREATE TABLE {{=it.entity.defKey}}(\n{{ pkList = [] ; }}\n{{~it.entity.fields:field:index}}\n {{? field.primaryKey }}{{ pkList.push(field.defKey) }}{{?}}\n {{=field.defKey}} {{? field.autoIncrement}}SERIAL{{??}}{{=field.type}}{{?field.len>0}}{{='('}}{{=field.len}}{{?field.scale>0}}{{=','}}{{=field.scale}}{{?}}{{=')'}}{{?}}{{?}}{{= field.notNull ? ' NOT NULL' : '' }}{{= field.defaultValue ? it.func.join(' DEFAULT ',field.defaultValue,' ') : '' }}{{= index < it.entity.fields.length-1 ? ',' : ( pkList.length>0 ? ',' :'' ) }}\n{{~}}\n{{? pkList.length >0 }}\n PRIMARY KEY ({{~pkList:pkName:i}}{{= pkName }}{{= i'+(after.defKey||'NULL'));\n }\n if(before.defName !== after.defName){\n ret.push('显示名称:'+(before.defName||'NULL')+'->'+(after.defName||'NULL'));\n }\n if(before.comment !== after.comment){\n ret.push('说明:'+(before.comment||'NULL')+'->'+(after.comment||'NULL'));\n }\n if(ret.length>0){\n return ' 基本信息:\\n\\t'+ret.join('\\n\\t');\n }\n return '';\n };\n \n function buildAddedDesc(entity){\n let ret = [];\n let fieldAdded = entity.data.fieldAdded||[];\n \n for (let field of fieldAdded) { \n let row = [];\n row.push(field.defKey+'['+field.defName+']');\n ret.push(row.join(\"\"))\n }\n return ret;\n };\n \n function buildRemovedDesc(entity){\n let ret = [];\n let fieldRemoved = entity.data.fieldRemoved||[];\n \n for (let field of fieldRemoved) { \n let row = [];\n row.push(field.defKey+'['+field.defName+']');\n ret.push(row.join(\"\"))\n }\n return ret;\n };\n \n function buildModifiedDesc(entity){\n let ret = [];\n let fieldModified = entity.data.fieldModified||[];\n \n for (let field1 of fieldModified) { \n let row = [];\n let field = field1.before;\n row.push(field.defKey+'['+field.defName+']');\n ret.push(row.join(\"\"))\n }\n return ret;\n };\n}}\n\n\n{{? createEntities && createEntities.length > 0}}\n/* --------------- 创建表 --------------- */\n{{~ createEntities:entity}}\n{{=entity.data.defKey}}[{{=entity.data.defName}}]\n{{~}}\n{{?}}\n\n\n{{? dropEntities && dropEntities.length > 0}}\n/* --------------- 删除表 --------------- */\n{{~ dropEntities:entity}}\n{{=entity.data.defKey}}[{{=entity.data.defName}}]\n{{~}}\n{{?}}\n\n{{? modifyEntities && modifyEntities.length > 0}}\n/* --------------- 修改表 --------------- */\n{{~ modifyEntities:entity}}\n{{=entity.data.baseInfo.defKey}}[{{=entity.data.baseInfo.defName}}]{{let changeText=baseChanged(entity.data.baseChanged);}}\n{{=baseChanged(entity.data.baseChanged)}}\n {{? entity.data.fieldModified && entity.data.fieldModified.length > 0}}\n 修改字段:\n {{='\\t'}}{{=buildModifiedDesc(entity).join('\\n\\t')}}{{?}}{{\n /*计算是否调整了属性*/\n let propAdded = entity.data.propAdded || [];\n let propRemoved = entity.data.propRemoved || [];\n let propModified = entity.data.propModified || [];\n let changed = propAdded.length>0 || propRemoved.length>0 || propModified.length>0;\n /*计算关联是否调整*/\n let refEntityAdd = entity.data.refEntityAdd || [];\n let refEntityRemoved = entity.data.refEntityRemoved || [];\n let relaArray = [];\n for (let rela of refEntityAdd) {\n relaArray.push('建立关联:'+rela.defKey+'['+rela.defName+']');\n }\n for (let rela of refEntityRemoved) {\n relaArray.push('解除关联:'+rela.defKey+'['+rela.defName+']');\n }\n /*索引是否修改过*/\n let indexChanged = entity.data.indexChanged;\n }}{{=indexChanged?'\\n\\t更改了索引':''}}{{=changed?'\\n\\t更改了属性':''}}{{=relaArray.length>0?('\\n\\t'+relaArray.join('\\n\\t')):''}}\n{{? entity.data.fieldAdded && entity.data.fieldAdded.length > 0}}\n 添加字段:\n{{='\\t'}}{{=buildAddedDesc(entity).join('\\n\\t')}}\n{{?}}{{? entity.data.fieldRemoved && entity.data.fieldRemoved.length > 0}}\n 删除字段:\n{{='\\t'}}{{=buildRemovedDesc(entity).join('\\n\\t')}}\n{{?}}\n{{~}}\n{{?}}", + "update": "{{\n let createEntities = it.changes.filter(function(row){return (row.opt==='add'&&row['type']==='entity');});\n let dropEntities = it.changes.filter(function(row){return (row.opt==='delete'&&row['type']==='entity');});\n let modifyEntities = it.changes.filter(function(row){return (row.opt==='update'&&row['type']==='entity');});\n \n function baseChangedDDL(beforeAfter){\n if(beforeAfter == null){\n return '';\n }\n let ret = [];\n let before = beforeAfter.before || {\"defKey\":\"\",\"defName\":\"\",\"comment\":\"\"};\n let after = beforeAfter.after || {\"defKey\":\"\",\"defName\":\"\",\"comment\":\"\"};\n if(before.defKey !== after.defKey){\n ret.push(`ALTER TABLE ${before.defKey} RENAME TO ${after.defKey}`);\n }\n let commentText = '';\n let commentChanged = false;\n if(before.defName !== after.defName){\n commentText = after.defName;\n commentChanged = true;\n }\n if(before.comment !== after.comment){\n commentChanged = true;\n if(commentText){\n commentText = (commentText+ ';'+after.comment)\n }else{\n commentText = after.comment\n }\n }\n if(commentChanged){\n let myText = `COMMENT ON TABLE ${after.defKey} IS '${commentText}'`;\n ret.push(myText);\n }\n let baseText = '-- 基本信息:\\n';\n return baseText+ret.join(';\\n')+';';\n };\n \n function buildAddedDDL(entity){\n let ret = [];\n let fieldAdded = entity.data.fieldAdded||[];\n if(fieldAdded.length == 0){\n return '';\n }\n \n let firstDDL = `ALTER TABLE ${entity.data.baseInfo.defKey}`;\n for (let field of fieldAdded) { \n let ddlItem = `ADD COLUMN ${field.defKey} ${field.dbType}`;\n /*处理数据类型长度*/\n if(field.len>0){\n ddlItem += ('('+field.len);\n if(parseInt(field.scale)>0){\n ddlItem += (','+field.scale);\n }\n ddlItem += ')';\n }\n if(field.notNull){\n ddlItem += ' NOT NULL';\n } \n let defaultValue = field.defaultValue;\n defaultValue = (defaultValue==null)?\"\":(\"\"+defaultValue);\n if(defaultValue.length>0){\n ddlItem += (' DEFAULT ' + defaultValue);\n }\n\n ret.push(`${firstDDL} ${ddlItem}`);\n \n /*处理字段注释*/\n let fieldComments = [];\n if(field.defName != null &&field.defName.length>0){\n fieldComments.push(field.defName);\n }\n if(field.comment != null &&field.comment.length>0){\n fieldComments.push(field.comment);\n }\n let commentText = fieldComments.join(';');\n if(commentText != null && commentText.length > 0){\n let commentDDL = `COMMENT ON COLUMN ${entity.data.baseInfo.defKey}.${field.defKey} IS '${commentText}'`;\n ret.push(commentDDL);\n }\n }\n return '\\n'+ret.join(';\\n');\n };\n \n function buildRemovedDDL(entity){\n let ret = [];\n let fieldRemoved = entity.data.fieldRemoved||[];\n if(fieldRemoved.length == 0){\n return '';\n }\n \n let firstDDL = `ALTER TABLE ${entity.data.baseInfo.defKey}`;\n for (let field of fieldRemoved) { \n ret.push(`${firstDDL} DROP COLUMN ${field.defKey}`);\n }\n return '\\n'+ret.join(';\\n');\n };\n \n function buildModifiedDDL(entity){\n let ret = [];\n let fieldModified = entity.data.fieldModified||[];\n \n let firstDDL = `ALTER TABLE ${entity.data.baseInfo.defKey}`;\n for (let field of fieldModified) { \n let before = field.before || {};\n let after = field.after || {};\n if(before.defKey !== after.defKey){\n let renameText = `ALTER TABLE ${entity.data.baseInfo.defKey} RENAME COLUMN ${before.defKey} TO ${after.defKey};`;\n ret.push(renameText);\n }\n /*如果没有变化,则不生成变更语句*/\n if(before.dbType === after.dbType \n && before['len'] === after['len'] \n && before.scale === after.scale\n && before.primaryKey === after.primaryKey\n && before.notNull === after.notNull\n && before.autoIncrement === after.autoIncrement\n && before.defaultValue === after.defaultValue){\n continue;\n }\n if(before.dbType !== after.dbType || before.len !== after.len || before.scale !== after.scale){\n let dbTypeDDL = `ALTER TABLE ${entity.data.baseInfo.defKey} ALTER COLUMN ${after.defKey} TYPE ${before.dbType}`;\n if(after.len>0){\n dbTypeDDL += ('('+after.len);\n if(parseInt(after.scale)>0){\n dbTypeDDL += (','+after.scale);\n }\n dbTypeDDL += ')';\n }\n ret.push(dbTypeDDL+';');\n }\n \n if(before.defaultValue !== after.defaultValue){\n let defaultDDL = '';\n let defaultValue = after.defaultValue;\n defaultValue = (defaultValue==null)?\"NULL\":(\"\"+defaultValue);\n if(defaultValue.length>0){\n defaultDDL += ('SET DEFAULT ' + defaultValue);\n }\n let defaultTpl = `ALTER TABLE ${entity.data.baseInfo.defKey} ALTER COLUMN ${defaultDDL};`;\n ret.push(defaultTpl);\n }\n \n if(before.notNull !== after.notNull){\n let notNullDDL= 'SET NULL';\n if(after.notNull){\n let notNullDDL= 'SET NOT NULL';\n }\n let notNullTpl = `ALTER TABLE ${entity.data.baseInfo.defKey} ALTER COLUMN ${notNullDDL};`;\n ret.push(notNullTpl);\n }\n }\n return ret;\n };\n}}\n{{? createEntities && createEntities.length > 0}}\n/* --------------- 创建表 --------------- */\n{{~ createEntities:entity}}\n{{=it.func.createDDL(entity.data,entity['type'])}}\n{{~}}\n{{?}}\n\n\n{{? dropEntities && dropEntities.length > 0}}\n/* --------------- 删除表 --------------- */\n{{~ dropEntities:entity}}\n{{=it.func.dropDDL(entity.data,entity['type'])}}\n{{~}}\n{{?}}\n\n\n{{? modifyEntities && modifyEntities.length > 0}}\n{{~ modifyEntities:entity}}\n/* --------------- 修改表 --------------- */\n-- 修改表:{{=entity.data.baseInfo.defKey}}[{{=entity.data.baseInfo.defName}}]\n{{=baseChangedDDL(entity.data.baseChanged)}}\n{{? entity.data.fieldModified && entity.data.fieldModified.length > 0}}\n-- 修改字段:\n{{=buildModifiedDDL(entity).join('\\n')}}\n{{?}}{{\n/*索引是否修改过*/\nlet indexChanged = entity.data.indexChanged;\n}}\n{{? indexChanged }}\n-- 索引重建\n{{=it.func.indexRebuildDDL(entity.data.baseInfo,entity.data.newIndexes,entity.data.fullFields,entity['type'])}}\n{{?}}\n\n{{? entity.data.fieldAdded && entity.data.fieldAdded.length > 0}}\n-- 添加字段:\n{{=buildAddedDDL(entity)}};\n{{?}}\n\n{{? entity.data.fieldRemoved && entity.data.fieldRemoved.length > 0}}\n-- 删除字段:\n{{=buildRemovedDDL(entity)}};\n{{?}}\n{{~}}\n{{?}}" + }, + { + "type": "dbDDL", + "applyFor": "89504F5D-94BF-4C9E-8B2E-44F37305FED5", + "createTable": "CREATE TABLE {{=it.entity.defKey}}(\n{{ pkList = [] ; }}\n{{~it.entity.fields:field:index}}\n {{? field.primaryKey }}{{ pkList.push(field.defKey) }}{{?}}\n {{=field.defKey}} {{=field.type}}{{?field.len>0}}{{='('}}{{=field.len}}{{?field.scale>0}}{{=','}}{{=field.scale}}{{?}}{{=')'}}{{?}}{{= field.notNull ? ' NOT NULL' : '' }}{{= field.autoIncrement ? '' : '' }}{{= field.defaultValue ? it.func.join(' DEFAULT ',field.defaultValue,' ') : '' }}{{= index < it.entity.fields.length-1 ? ',' : ( pkList.length>0 ? ',' :'' ) }}\n{{~}}\n{{? pkList.length >0 }}\n PRIMARY KEY ({{~pkList:pkName:i}}{{= pkName }}{{= i0}}{{='('}}{{=field.len}}{{?field.scale>0}}{{=','}}{{=field.scale}}{{?}}{{=')'}}{{?}} {{= field.notNull ? 'NOT NULL' : '' }} {{= field.autoIncrement ? 'IDENTITY(1,1)' : '' }}{{= field.defaultValue ? it.func.join(' DEFAULT ',field.defaultValue,' ') : '' }} COMMENT '{{=it.func.join(field.defName,field.comment,';')}}'{{= index < it.entity.fields.length-1 ? ',' : ( pkList.length>0 ? ',' :'' ) }}\n{{~}}\n{{? pkList.length >0 }}\n PRIMARY KEY ({{~pkList:pkName:i}}{{= pkName }}{{= i0}}{{='('}}{{=field.len}}{{?field.scale>0}}{{=','}}{{=field.scale}}{{?}}{{=')'}}{{?}}{{= field.notNull ? ' NOT NULL' : '' }}{{= field.autoIncrement ? ' AUTO_INCREMENT' : '' }}{{= field.defaultValue ? it.func.join(' DEFAULT ',field.defaultValue,' ') : '' }}{{= index < it.entity.fields.length-1 ? ',' : ( pkList.length>0 ? ',' :'' ) }}\n{{~}}\n{{? pkList.length >0 }}\n PRIMARY KEY ({{~pkList:pkName:i}}{{= pkName }}{{= i0}}{{='('}}{{=field.len}}{{?field.scale>0}}{{=','}}{{=field.scale}}{{?}}{{=')'}}{{= field.defaultValue ? it.func.join(' DEFAULT ',field.defaultValue,' ') : '' }}{{?}}{{= field.notNull ? ' NOT NULL' : '' }}{{= index < it.entity.fields.length-1 ? ',' : ( pkList.length>0 ? ',' :'' ) }}\n{{~}}\n{{? pkList.length >0 }}\n PRIMARY KEY ({{~pkList:pkName:i}}{{= pkName }}{{= i0 ? ',' :'' ) }}\n{{~}}\n{{? pkList.length >0 }}\n PRIMARY KEY ({{~pkList:pkName:i}}{{= pkName }}{{= i0}}{{='('}}{{=field.len}}{{?field.scale>0}}{{=','}}{{=field.scale}}{{?}}{{=')'}}{{?}} {{= field.notNull ? 'NOT NULL' : '' }} {{= field.autoIncrement ? 'AUTOINCREMENT' : '' }} {{= field.defaultValue ? it.func.join('DEFAULT',field.defaultValue,' ') : '' }}{{= index < it.entity.fields.length-1 ? ',' : ( pkList.length>0 ? ',' :'' ) }} --{{=it.func.join(field.defName,field.comment,';')}}\n{{~}}\n{{? pkList.length >0 }}\n PRIMARY KEY ({{~pkList:pkName:i}}{{= pkName }}{{= i0只有为decimal类型或double类型时才保留长度和小数的位数*/\n{{~it.entity.fields:field:index}}\n {{=it.func.lowerCase(field.defKey)}} {{=it.func.lowerCase(field.type)=='varchar'||it.func.lowerCase(field.type)=='char'||it.func.lowerCase(field.type)=='text'||it.func.lowerCase(field.type)=='date'||it.func.lowerCase(field.type)=='datetime' ? 'string':it.func.lowerCase(field.type)=='tinyint unsigned'||it.func.lowerCase(field.type)=='bit'||it.func.lowerCase(field.type)=='integer'||it.func.lowerCase(field.type)=='tinyint'||it.func.lowerCase(field.type)=='smallint'||it.func.lowerCase(field.type)=='mediumint' ? 'int':it.func.lowerCase(field.type)=='int unsigned' ? 'bigint':it.func.lowerCase(field.type)}}{{?field.len>0&&(it.func.lowerCase(field.type)=='decimal'||it.func.lowerCase(field.type)=='double')}}{{='('}}{{=field.len}}{{?field.scale>0}}{{=','}}{{=field.scale}}{{=')'}}{{?}}{{?}} comment '{{=it.func.join(field.defName,field.comment,'')}}' {{= index < it.entity.fields.length-1 ? ',' : ( pkList.length>0 ? ',' :'' ) }}\n{{~}}\n{{? pkList.length >0 }}\n{{?}}\n)\n{{\n let partitionedBy = it.entity.properties['partitioned by'];\n partitionedBy = partitionedBy?partitionedBy:'请在扩展属性中配置[partitioned by]属性';\n}}\ncomment '{{=it.func.join(it.entity.defName,';') }}'\n/**是否分区表,分区字段名和字段注释自定义*/\n[partitioned by {{=partitionedBy}}]\n/**文件存储格式自定义*/\n[stored as orc]\n/**hdfs上的地址自定义*/\n[location xxx]\n;", + "createView": "", + "deleteTable": "", + "createIndex": "", + "deleteIndex": "", + "message": "", + "update": "" + }, + { + "applyFor": "B91D99E0-9B7C-416C-8737-B760957DAF09", + "type": "appCode", + "content": "{{\n var today=new Date();\n var fullYear=today.getFullYear();\n var month=today.getMonth() + 1<10?\"0\"+today.getMonth():today.getMonth();\n var days=today.getDate()<10?\"0\"+today.getDate():today.getDate();\n var hours = today.getHours()<10?\"0\"+today.getHours():today.getHours(); \n\tvar minutes = today.getMinutes()<10?\"0\"+today.getMinutes():today.getMinutes(); \n\tvar seconds = today.getSeconds()<10?\"0\"+today.getSeconds():today.getSeconds(); \n}}\n// Package models {{=it.func.join(it.entity.defName,it.entity.comment,',')}}\n// author : http://www.liyang.love\n// date : {{=fullYear}}-{{=month}}-{{=days}} {{=hours}}:{{=minutes}}\n// desc : {{=it.func.join(it.entity.defName,it.entity.comment,',')}}\npackage models\n\n$blankline\n\n// {{=it.func.camel(it.entity.defKey,true) }} {{=it.func.join(it.entity.defName,it.entity.comment,',')}}。\n// 说明:{{=it.entity.comment}}\n// 表名:{{=it.entity.defKey}}\n// group: {{=it.func.camel(it.entity.defKey,true) }}\n// obsolete:\n// appliesto:go 1.8+;\n// namespace:hongmouer.his.models.{{=it.func.camel(it.entity.defKey,true) }}\n// assembly: hongmouer.his.models.go\n// class:HongMouer.HIS.Models.{{=it.func.camel(it.entity.defKey,true) }}\n// version:{{=fullYear}}-{{=month}}-{{=days}} {{=hours}}:{{=minutes}}\ntype {{=it.func.camel(it.entity.defKey,true) }} struct {\n {{~it.entity.fields:field:index}}\n {{=formatGoLang(it.func.camel(field.defKey,true),null,field,it.entity.fields,null,1)}} {{=formatGoLang(field.type,\"type\",field,it.entity.fields,10,3)}} `gorm:\"column:{{=field.primaryKey?\"primaryKey;\":\"\"}}{{=field.defKey}}\" json:\"{{=it.func.camel(field.defKey,true)}}\"` {{=formatGoLang(\"gorm:column:\"+field.defKey+\" json:\"+it.func.camel(field.defKey,true),null,field,it.entity.fields,null,2)}} //type:{{=formatGoLang(field.type,\"type\",field,it.entity.fields,null,3)}} comment:{{=formatGoLang(it.func.join(field.defName,field.comment,';'),\"defName\",field,it.entity.fields,null,4)}} version:{{=fullYear}}-{{=month}}-{{=days}} {{=hours}}:{{=minutes}}\n {{~}}\n}\n\n\n$blankline\n// TableName 表名:{{=it.entity.defKey}},{{=it.entity.defName}}。\n// 说明:{{=it.entity.comment}}\nfunc (ZentaoUserInfo) TableName() string {\n\treturn \"{{=it.entity.defKey}}\"\n}\n\n{{\n\nfunction formatGoLang(str, fieldName, field, fileds, emptLength, isFiled) {\n var maxLength = 0;\n\n if (isFiled == 1) {\n for (var i = 0; i < fileds.length; i++) {\n if (getBlength(it.func.camel(fileds[i].defKey, true)) > maxLength) {\n maxLength = getBlength(it.func.camel(fileds[i].defKey, true)) + 2;\n }\n }\n } else if (isFiled == 2) {\n for (var i = 0; i < fileds.length; i++) {\n var newStr = \"gorm:column:\" + fileds[i].defKey + \" json:\" + it.func.camel(fileds[i].defKey, true);\n if (getBlength(newStr) > maxLength) {\n maxLength = getBlength(newStr) + 2;\n }\n }\n var empt = \"\";\n var strLength = getBlength(str);\n if (field.primaryKey) {\n strLength += getBlength(\"primaryKey;\");\n }\n for (var j = 0; j < maxLength - strLength; j++) {\n empt += ' ';\n }\n return empt;\n } else if (isFiled == 3) {\n /*获取某个字段的最大长度*/\n for (var i = 0; i < fileds.length; i++) {\n var newStr = eval(\"fileds[\" + i + \"].\" + fieldName);\n if (getBlength(newStr) > maxLength) {\n maxLength = getBlength(newStr) + 1;\n }\n }\n } else if (isFiled == 4) {\n /*获取某个字段的最大长度*/\n for (var i = 0; i < fileds.length; i++) {\n var newStr = fileds[i].comment + \";\" + fileds[i].defName;\n if (getBlength(newStr) > maxLength) {\n maxLength = getBlength(newStr) + 1;\n }\n }\n }\n else {\n maxLength = emptLength;\n }\n\n var strLength = getBlength(str);\n for (var j = 0; j < maxLength - strLength; j++) {\n str += ' ';\n }\n return str;\n}\n\nfunction getBlength(str) {\n var n = 0;\n for (var i = str.length; i--;) {\n n += str.charCodeAt(i) > 255 ? 2 : 1;\n }\n return n;\n} \n\n}}" + }, + { + "applyFor": "BDF457FD-9F98-4AC3-A705-7587B00A3BAB", + "type": "appCode", + "struct": "use chrono::{DateTime, Local};\nuse serde::{Deserialize, Serialize};\n$blankline\n/// {{=it.entity.defName}}\n#[derive(Serialize, Deserialize, Debug, Clone)]\n{{ var today=new Date();\n var fullYear=today.getFullYear();\n var month=today.getMonth() + 1;\n var days=today.getDate();\n \n var pkVarName = \"undefinedId\";\n var pkDataType = \"String\";\n it.entity.fields.forEach(function(field){\n if(field.primaryKey){\n pkVarName = it.func.camel(field.defKey,false);\n pkDataType = field[\"type\"];\n return;\n }\n });\n \n var pkgName = it.entity.env.base.nameSpace;\n var beanClass = it.entity.env.base.codeRoot;\n var beanVarName = beanClass.charAt(0).toLowerCase()+beanClass.slice(1);\n \n}}\npub struct {{=beanClass}} {\n {{~it.entity.fields:field:index}}\n {{\n let fieldDateType = field.type;\n if(!field.notNull){\n fieldDateType = 'Option<'+fieldDateType+'>';\n }\n }}/// {{=field.defName}}\n pub {{=it.func.camel(field.defKey,false)}}: {{=fieldDateType}},\n {{~}}\n}\n" + }, + { + "applyFor": "56F4B55B-F0B8-4049-9E6B-50B95C1D793A", + "type": "dbDDL", + "createTable": "CREATE TABLE {{=it.entity.defKey}}(\n{{ pkList = [] ; }}\n{{~it.entity.fields:field:index}}\n {{? field.primaryKey }}{{ pkList.push(field.defKey) }}{{?}}\n {{=field.defKey}} {{=field.type}}{{?field.len>0}}{{='('}}{{=field.len}}{{?field.scale>0}}{{=','}}{{=field.scale}}{{?}}{{=')'}}{{?}}{{= field.defaultValue ? it.func.join(' DEFAULT ',field.defaultValue,' ') : '' }}{{= field.notNull ? ' NOT NULL' : '' }}{{= field.autoIncrement ? '' : '' }}{{= index < it.entity.fields.length-1 ? ',' : ( pkList.length>0 ? ',' :'' ) }}\n{{~}}\n{{? pkList.length >0 }}\n PRIMARY KEY ({{~pkList:pkName:i}}{{= pkName }}{{= i'+(after.defKey||'NULL'));\n }\n if(before.defName !== after.defName){\n ret.push('显示名称:'+(before.defName||'NULL')+'->'+(after.defName||'NULL'));\n }\n if(before.comment !== after.comment){\n ret.push('说明:'+(before.comment||'NULL')+'->'+(after.comment||'NULL'));\n }\n if(ret.length>0){\n return ' 基本信息:\\n\\t'+ret.join('\\n\\t');\n }\n return '';\n };\n \n function buildAddedDesc(entity){\n let ret = [];\n let fieldAdded = entity.data.fieldAdded||[];\n \n for (let field of fieldAdded) { \n let row = [];\n row.push(field.defKey+'['+field.defName+']');\n ret.push(row.join(\"\"))\n }\n return ret;\n };\n \n function buildRemovedDesc(entity){\n let ret = [];\n let fieldRemoved = entity.data.fieldRemoved||[];\n \n for (let field of fieldRemoved) { \n let row = [];\n row.push(field.defKey+'['+field.defName+']');\n ret.push(row.join(\"\"))\n }\n return ret;\n };\n \n function buildModifiedDesc(entity){\n let ret = [];\n let fieldModified = entity.data.fieldModified||[];\n \n for (let field1 of fieldModified) { \n let row = [];\n let field = field1.before;\n row.push(field.defKey+'['+field.defName+']');\n ret.push(row.join(\"\"))\n }\n return ret;\n };\n}}\n{{? createEntities && createEntities.length > 0}}\n/* -------------------------------------------------- */\n创建表:\n{{~ createEntities:entity}}\n {{=entity.data.defKey}}[{{=entity.data.defName}}]\n{{~}}\n{{?}}\n\n\n{{? dropEntities && dropEntities.length > 0}}\n/* -------------------------------------------------- */\n删除表:\n{{~ dropEntities:entity}}\n {{=entity.data.defKey}}[{{=entity.data.defName}}]\n{{~}}\n{{?}}\n\n\n{{? modifyEntities && modifyEntities.length > 0}}\n{{~ modifyEntities:entity}}\n/* -------------------------------------------------- */\n修改表:{{=entity.data.baseInfo.defKey}}[{{=entity.data.baseInfo.defName}}]{{let changeText=baseChanged(entity.data.baseChanged);}}\n{{=baseChanged(entity.data.baseChanged)}}\n {{? entity.data.fieldAdded && entity.data.fieldAdded.length > 0}}\n 添加字段:\n {{='\\t'}}{{=buildAddedDesc(entity).join('\\n\\t')}}\n {{?}}{{? entity.data.fieldRemoved && entity.data.fieldRemoved.length > 0}}\n 删除字段:\n {{='\\t'}}{{=buildRemovedDesc(entity).join('\\n\\t')}}\n {{?}}{{? entity.data.fieldModified && entity.data.fieldModified.length > 0}}\n 修改字段:\n {{='\\t'}}{{=buildModifiedDesc(entity).join('\\n\\t')}}\n {{?}}{{\n /*计算是否调整了属性*/\n let propAdded = entity.data.propAdded || [];\n let propRemoved = entity.data.propRemoved || [];\n let propModified = entity.data.propModified || [];\n let changed = propAdded.length>0 || propRemoved.length>0 || propModified.length>0;\n /*计算关联是否调整*/\n let refEntityAdd = entity.data.refEntityAdd || [];\n let refEntityRemoved = entity.data.refEntityRemoved || [];\n let relaArray = [];\n for (let rela of refEntityAdd) {\n relaArray.push('\\n\\t建立关联:'+rela.defKey+'['+rela.defName+']');\n }\n for (let rela of refEntityRemoved) {\n relaArray.push('\\n\\t解除关联:'+rela.defKey+'['+rela.defName+']');\n }\n /*索引是否修改过*/\n let indexChanged = entity.data.indexChanged;\n }}\n{{=indexChanged?'\\n\\t更改了索引':''}}\n{{=changed?'\\n\\t更改了属性':''}}\n{{=relaArray.length>0?relaArray.join(''):''}}\n{{~}}\n{{?}}", + "update": "{{\n let createEntities = it.changes.filter(function(row){return (row.opt==='add'&&row['type']==='entity');});\n let dropEntities = it.changes.filter(function(row){return (row.opt==='delete'&&row['type']==='entity');});\n let modifyEntities = it.changes.filter(function(row){return (row.opt==='update'&&row['type']==='entity');});\n \n function baseChangedDDL(beforeAfter){\n if(beforeAfter == null){\n return '';\n }\n let ret = [];\n let before = beforeAfter.before || {\"defKey\":\"\",\"defName\":\"\",\"comment\":\"\"};\n let after = beforeAfter.after || {\"defKey\":\"\",\"defName\":\"\",\"comment\":\"\"};\n if(before.defKey !== after.defKey){\n ret.push(`ALTER TABLE ${before.defKey} RENAME TO ${after.defKey}`);\n }\n let commentText = '';\n let commentChanged = false;\n if(before.defName !== after.defName){\n commentText = after.defName;\n commentChanged = true;\n }\n if(before.comment !== after.comment){\n commentChanged = true;\n if(commentText){\n commentText = (commentText+ ';'+after.comment)\n }else{\n commentText = after.comment\n }\n }\n if(commentChanged){\n let myText = `COMMENT ON TABLE ${after.defKey} IS '${commentText}'`;\n ret.push(myText);\n }\n let baseText = '-- 基本信息:\\n';\n return baseText+ret.join(';\\n')+';';\n };\n \n function buildAddedDDL(entity){\n let ret = [];\n let fieldAdded = entity.data.fieldAdded||[];\n if(fieldAdded.length == 0){\n return '';\n }\n \n let firstDDL = `ALTER TABLE ${entity.data.baseInfo.defKey}`;\n for (let field of fieldAdded) { \n let ddlItem = `ADD (${field.defKey} ${field.dbType}`;\n /*处理数据类型长度*/\n if(field.len>0){\n ddlItem += ('('+field.len);\n if(parseInt(field.scale)>0){\n ddlItem += (','+field.scale);\n }\n ddlItem += ')';\n }\n let defaultValue = field.defaultValue;\n defaultValue = (defaultValue==null)?\"\":(\"\"+defaultValue);\n if(defaultValue.length>0){\n ddlItem += (' DEFAULT ' + defaultValue);\n }\n if(field.notNull){\n ddlItem += ' NOT NULL';\n }\n ddlItem += ')';\n ret.push(`${firstDDL} ${ddlItem}`);\n \n /*处理字段注释*/\n let fieldComments = [];\n if(field.defName != null &&field.defName.length>0){\n fieldComments.push(field.defName);\n }\n if(field.comment != null &&field.comment.length>0){\n fieldComments.push(field.comment);\n }\n let commentText = fieldComments.join(';');\n if(commentText != null && commentText.length > 0){\n let commentDDL = `COMMENT ON COLUMN ${entity.data.baseInfo.defKey}.${field.defKey} IS '${commentText}'`;\n ret.push(commentDDL);\n }\n }\n return '\\n'+ret.join(';\\n');\n };\n \n function buildRemovedDDL(entity){\n let ret = [];\n let fieldRemoved = entity.data.fieldRemoved||[];\n if(fieldRemoved.length == 0){\n return '';\n }\n \n let firstDDL = `ALTER TABLE ${entity.data.baseInfo.defKey}`;\n for (let field of fieldRemoved) { \n ret.push(`${firstDDL} DROP COLUMN ${field.defKey}`);\n }\n return '\\n'+ret.join(';\\n');\n };\n \n function buildModifiedDDL(entity){\n let ret = [];\n let fieldModified = entity.data.fieldModified||[];\n \n let firstDDL = `ALTER TABLE ${entity.data.baseInfo.defKey}`;\n for (let field of fieldModified) { \n let changeDDL = '';\n let before = field.before || {};\n let after = field.after || {};\n if(before.defKey !== after.defKey){\n let renameText = `ALTER TABLE ${entity.data.baseInfo.defKey} RENAME COLUMN ${before.defKey} TO ${after.defKey};`;\n ret.push(renameText);\n }\n /*如果没有变化,则不生成变更语句*/\n if(before.dbType === after.dbType \n && before['len'] === after['len'] \n && before.scale === after.scale\n && before.primaryKey === after.primaryKey\n && before.notNull === after.notNull\n && before.autoIncrement === after.autoIncrement\n && before.defaultValue === after.defaultValue){\n continue;\n }\n changeDDL += ('MODIFY ('+after.defKey+'');\n changeDDL += (' '+after.dbType);\n if(after.len>0){\n changeDDL += ('('+after.len);\n if(parseInt(after.scale)>0){\n changeDDL += (','+after.scale);\n }\n changeDDL += ')';\n }\n let defaultValue = after.defaultValue;\n defaultValue = (defaultValue==null)?\"\":(\"\"+defaultValue);\n if(defaultValue.length>0){\n changeDDL += (' DEFAULT ' + defaultValue);\n }\n \n if(after.notNull){\n changeDDL += ' NOT NULL';\n }\n changeDDL += ')';\n ret.push(`${firstDDL} ${changeDDL};`);\n }\n return ret;\n };\n}}\n{{? createEntities && createEntities.length > 0}}\n/* --------------- 创建表 --------------- */\n{{~ createEntities:entity}}\n{{=it.func.createDDL(entity.data,entity['type'])}}\n{{~}}\n{{?}}\n\n\n{{? dropEntities && dropEntities.length > 0}}\n/* --------------- 删除表 --------------- */\n{{~ dropEntities:entity}}\n{{=it.func.dropDDL(entity.data,entity['type'])}}\n{{~}}\n{{?}}\n\n\n{{? modifyEntities && modifyEntities.length > 0}}\n{{~ modifyEntities:entity}}\n/* --------------- 修改表 --------------- */\n-- 修改表:{{=entity.data.baseInfo.defKey}}[{{=entity.data.baseInfo.defName}}]\n{{=baseChangedDDL(entity.data.baseChanged)}}\n{{? entity.data.fieldModified && entity.data.fieldModified.length > 0}}\n-- 修改字段:\n{{=buildModifiedDDL(entity).join('\\n')}}\n{{?}}{{\n/*索引是否修改过*/\nlet indexChanged = entity.data.indexChanged;\n}}\n{{? indexChanged }}\n{{=it.func.indexRebuildDDL(entity.data.baseInfo,entity.data.newIndexes,entity.data.fullFields,entity['type'])}}\n{{?}}\n\n{{? entity.data.fieldAdded && entity.data.fieldAdded.length > 0}}\n-- 添加字段:\n{{=buildAddedDDL(entity)}};\n{{?}}\n\n{{? entity.data.fieldRemoved && entity.data.fieldRemoved.length > 0}}\n-- 删除字段:\n{{=buildRemovedDDL(entity)}};\n{{?}}\n{{~}}\n{{?}}" + }, + { + "applyFor": "483F9346-C99E-4014-A1D2-A554606BD8A3", + "type": "dbDDL", + "createTable": "{{let dorisDistributedBy = it.entity.properties['dorisDistributedBy'];\n dorisDistributedBy = dorisDistributedBy?dorisDistributedBy:'请在表的扩展属性中配置[dorisDistributedBy]属性';\n}}CREATE TABLE IF NOT EXISTS {{=it.entity.defKey}}(\n{{ pkList = [] ; }}\n{{~it.entity.fields:field:index}}\n {{? field.primaryKey }}{{ pkList.push(field.defKey) }}{{?}}\n `{{=field.defKey}}` {{=field.type}}{{?field.len>0}}{{='('}}{{=field.len}}{{?field.scale>0}}{{=','}}{{=field.scale}}{{?}}{{=')'}}{{?}} {{= field.notNull ? 'NOT NULL' : '' }} COMMENT '{{=it.func.join(field.defName,field.comment,';')}}' {{= index < it.entity.fields.length-1 ? ',' : '' }}\n{{~}}\n) COMMENT '{{=it.func.join(it.entity.defName,it.entity.comment,';') }}'\n{{=dorisDistributedBy}} ;\n$blankline\n", + "createView": "", + "deleteTable": "DROP TABLE IF EXISTS {{=it.entity.defKey}};", + "createIndex": "", + "deleteIndex": "", + "message": "{{\n let createEntities = it.changes.filter(function(row){return (row.opt==='add'&&row['type']==='entity');});\n let dropEntities = it.changes.filter(function(row){return (row.opt==='delete'&&row['type']==='entity');});\n let modifyEntities = it.changes.filter(function(row){return (row.opt==='update'&&row['type']==='entity');});\n \n function baseChanged(beforeAfter){\n if(beforeAfter == null){\n return '';\n }\n let ret = [];\n let before = beforeAfter.before || {\"defKey\":\"\",\"defName\":\"\",\"comment\":\"\"};\n let after = beforeAfter.after || {\"defKey\":\"\",\"defName\":\"\",\"comment\":\"\"};\n if(before.defKey !== after.defKey){\n ret.push('代码:'+(before.defKey||'NULL')+'->'+(after.defKey||'NULL'));\n }\n if(before.defName !== after.defName){\n ret.push('显示名称:'+(before.defName||'NULL')+'->'+(after.defName||'NULL'));\n }\n if(before.comment !== after.comment){\n ret.push('说明:'+(before.comment||'NULL')+'->'+(after.comment||'NULL'));\n }\n if(ret.length>0){\n return ' 基本信息:\\n\\t'+ret.join('\\n\\t');\n }\n return '';\n };\n \n function buildAddedDesc(entity){\n let ret = [];\n let fieldAdded = entity.data.fieldAdded||[];\n \n for (let field of fieldAdded) { \n let row = [];\n row.push(field.defKey+'['+field.defName+']');\n ret.push(row.join(\"\"))\n }\n return ret;\n };\n \n function buildRemovedDesc(entity){\n let ret = [];\n let fieldRemoved = entity.data.fieldRemoved||[];\n \n for (let field of fieldRemoved) { \n let row = [];\n row.push(field.defKey+'['+field.defName+']');\n ret.push(row.join(\"\"))\n }\n return ret;\n };\n \n function buildModifiedDesc(entity){\n let ret = [];\n let fieldModified = entity.data.fieldModified||[];\n \n for (let field1 of fieldModified) { \n let row = [];\n let field = field1.before;\n row.push(field.defKey+'['+field.defName+']');\n ret.push(row.join(\"\"))\n }\n return ret;\n };\n}}\n\n\n{{? createEntities && createEntities.length > 0}}\n/* --------------- 创建表 --------------- */\n{{~ createEntities:entity}}\n{{=entity.data.defKey}}[{{=entity.data.defName}}]\n{{~}}\n{{?}}\n\n\n{{? dropEntities && dropEntities.length > 0}}\n/* --------------- 删除表 --------------- */\n{{~ dropEntities:entity}}\n{{=entity.data.defKey}}[{{=entity.data.defName}}]\n{{~}}\n{{?}}\n\n{{? modifyEntities && modifyEntities.length > 0}}\n/* --------------- 修改表 --------------- */\n{{~ modifyEntities:entity}}\n{{=entity.data.baseInfo.defKey}}[{{=entity.data.baseInfo.defName}}]{{let changeText=baseChanged(entity.data.baseChanged);}}\n{{=baseChanged(entity.data.baseChanged)}}\n {{? entity.data.fieldModified && entity.data.fieldModified.length > 0}}\n 修改字段:\n {{='\\t'}}{{=buildModifiedDesc(entity).join('\\n\\t')}}{{?}}{{\n /*计算是否调整了属性*/\n let propAdded = entity.data.propAdded || [];\n let propRemoved = entity.data.propRemoved || [];\n let propModified = entity.data.propModified || [];\n let changed = propAdded.length>0 || propRemoved.length>0 || propModified.length>0;\n /*计算关联是否调整*/\n let refEntityAdd = entity.data.refEntityAdd || [];\n let refEntityRemoved = entity.data.refEntityRemoved || [];\n let relaArray = [];\n for (let rela of refEntityAdd) {\n relaArray.push('建立关联:'+rela.defKey+'['+rela.defName+']');\n }\n for (let rela of refEntityRemoved) {\n relaArray.push('解除关联:'+rela.defKey+'['+rela.defName+']');\n }\n /*索引是否修改过*/\n let indexChanged = entity.data.indexChanged;\n }}{{=indexChanged?'\\n\\t更改了索引':''}}{{=changed?'\\n\\t更改了属性':''}}{{=relaArray.length>0?('\\n\\t'+relaArray.join('\\n\\t')):''}}\n{{? entity.data.fieldAdded && entity.data.fieldAdded.length > 0}}\n 添加字段:\n{{='\\t'}}{{=buildAddedDesc(entity).join('\\n\\t')}}\n{{?}}{{? entity.data.fieldRemoved && entity.data.fieldRemoved.length > 0}}\n 删除字段:\n{{='\\t'}}{{=buildRemovedDesc(entity).join('\\n\\t')}}\n{{?}}\n{{~}}\n{{?}}\n", + "update": "{{\n let createEntities = it.changes.filter(function(row){return (row.opt==='add'&&row['type']==='entity');});\n let dropEntities = it.changes.filter(function(row){return (row.opt==='delete'&&row['type']==='entity');});\n let modifyEntities = it.changes.filter(function(row){return (row.opt==='update'&&row['type']==='entity');});\n \n function baseChangedDDL(beforeAfter){\n if(beforeAfter == null){\n return '';\n }\n let ret = [];\n let before = beforeAfter.before || {\"defKey\":\"\",\"defName\":\"\",\"comment\":\"\"};\n let after = beforeAfter.after || {\"defKey\":\"\",\"defName\":\"\",\"comment\":\"\"};\n if(before.defKey !== after.defKey){\n ret.push('ALTER TABLE '+before.defKey+' RENAME TO '+after.defKey);\n }\n let commentText = '';\n let commentChanged = false;\n if(before.defName !== after.defName){\n commentText = after.defName;\n commentChanged = true;\n }\n if(before.comment !== after.comment){\n commentChanged = true;\n if(commentText){\n commentText = (commentText+ ';'+after.comment)\n }else{\n commentText = after.comment\n }\n }\n if(commentChanged){\n ret.push('ALTER TABLE '+after.defKey+' COMMENT \\''+commentText+'\\'');\n }\n let baseText = '-- 基本信息:\\n';\n return baseText+ret.join(';\\n')+';';\n };\n \n function buildAddedDDL(entity){\n let ret = [];\n let fieldAdded = entity.data.fieldAdded||[];\n if(fieldAdded.length == 0){\n return '';\n }\n \n let firstDDL = 'ALTER TABLE '+entity.data.baseInfo.defKey;\n for (let field of fieldAdded) { \n let ddlItem = 'ADD COLUMN `'+field.defKey+'` '+field.dbType;\n /*处理数据类型长度*/\n if(field.len>0){\n ddlItem += ('('+field.len);\n if(parseInt(field.scale)>0){\n ddlItem += (','+field.scale);\n }\n ddlItem += ')';\n }\n if(field.notNull){\n ddlItem += ' NOT NULL';\n }\n if(field.autoIncrement){\n ddlItem += ' AUTO_INCREMENT';\n }\n if(field.defaultValue){\n ddlItem += (' DEFAULT ' + field.defaultValue);\n }\n ddlItem += (' COMMENT \\''+field.defName+';'+field.comment+'\\'');\n \n if(field.index>0 && field.afterFieldKey){\n ddlItem += (' AFTER '+field.afterFieldKey);\n }\n ret.push(ddlItem);\n }\n return firstDDL+'\\n'+ret.join(',\\n');\n };\n \n function buildRemovedDDL(entity){\n let ret = [];\n let fieldRemoved = entity.data.fieldRemoved||[];\n if(fieldRemoved.length == 0){\n return '';\n }\n \n let firstDDL = 'ALTER TABLE '+entity.data.baseInfo.defKey;\n for (let field of fieldRemoved) { \n ret.push('DROP '+field.defKey);\n }\n return firstDDL+'\\n'+ret.join(',\\n');\n };\n \n function buildModifiedDDL(entity){\n let ret = [];\n let fieldModified = entity.data.fieldModified||[];\n \n let firstDDL = 'ALTER TABLE '+entity.data.baseInfo.defKey;\n for (let field of fieldModified) { \n let changeDDL = '';\n let before = field.before || {};\n let after = field.after || {};\n if(before.defKey === after.defKey){\n changeDDL += (' MODIFY COLUMN `'+after.defKey+'`');\n }else{\n changeDDL += (' CHANGE COLUMN `'+before.defKey+'` `'+after.defKey+'`');\n }\n changeDDL += (' '+after.dbType);\n if(after.len>0){\n changeDDL += ('('+after.len);\n if(parseInt(after.scale)>0){\n changeDDL += (','+after.scale);\n }\n changeDDL += ')';\n }\n if(after.notNull){\n changeDDL += ' NOT NULL';\n }\n let defaultValue = '';\n if(after.defaultValue != null && after.defaultValue.length>0){\n defaultValue = (after.defaultValue);\n }else{\n defaultValue = 'NULL';\n }\n if(defaultValue != 'NULL'){\n changeDDL += (' DEFAULT ' + defaultValue);\n }\n\n let comment = after.defName;\n if(after.comment){\n comment = comment + ';' + (after.comment||'');\n }\n if(comment){\n changeDDL += (' COMMENT \\''+comment+'\\';');\n }\n \n ret.push(firstDDL+' '+changeDDL);\n }\n return ret;\n };\n}}\n{{? createEntities && createEntities.length > 0}}\n/* --------------- 创建表 --------------- */\n{{~ createEntities:entity}}\n{{=it.func.createDDL(entity.data,entity['type'])}}\n{{~}}\n{{?}}\n\n\n{{? dropEntities && dropEntities.length > 0}}\n/* --------------- 删除表 --------------- */\n{{~ dropEntities:entity}}\n{{=it.func.dropDDL(entity.data,entity['type'])}}\n{{~}}\n{{?}}\n\n\n{{? modifyEntities && modifyEntities.length > 0}}\n{{~ modifyEntities:entity}}\n/* --------------- 修改表 --------------- */\n-- 修改表:{{=entity.data.baseInfo.defKey}}[{{=entity.data.baseInfo.defName}}]\n{{=baseChangedDDL(entity.data.baseChanged)}}\n{{? entity.data.fieldModified && entity.data.fieldModified.length > 0}}\n-- 修改字段:\n{{=buildModifiedDDL(entity).join('\\n')}}\n{{?}}{{\n/*索引是否修改过*/\nlet indexChanged = entity.data.indexChanged;\n}}\n{{? indexChanged }}\n{{=it.func.indexRebuildDDL(entity.data.baseInfo,entity.data.newIndexes,entity.data.fullFields,entity['type'])}}\n{{?}}\n\n{{? entity.data.fieldAdded && entity.data.fieldAdded.length > 0}}\n-- 添加字段:\n{{=buildAddedDDL(entity)}};\n{{?}}\n\n{{? entity.data.fieldRemoved && entity.data.fieldRemoved.length > 0}}\n-- 删除字段:\n{{=buildRemovedDDL(entity)}};\n{{?}}\n{{~}}\n{{?}}" + }, + { + "type": "dbDDL", + "applyFor": "9D418CB9-BCD5-4C37-BE64-910C9F7FC6AE", + "isDefault": true, + "createTable": "DROP TABLE IF EXISTS {{=it.entity.defKey}};\nCREATE TABLE {{=it.entity.defKey}}(\n{{ pkList = [] ; }}\n{{~it.entity.fields:field:index}}\n {{? field.primaryKey }}{{ pkList.push(field.defKey) }}{{?}}\n {{=field.defKey}} {{=field.type}}{{?field.len>0}}{{='('}}{{=field.len}}{{?field.scale>0}}{{=','}}{{=field.scale}}{{?}}{{=')'}}{{?}} {{= field.notNull ? 'NOT NULL' : '' }} {{= field.autoIncrement ? 'AUTO_INCREMENT' : '' }} {{= field.defaultValue ? it.func.join('DEFAULT',field.defaultValue,' ') : '' }} COMMENT '{{=it.func.join(field.defName,field.comment,';')}}' {{= index < it.entity.fields.length-1 ? ',' : ( pkList.length>0 ? ',' :'' ) }}\n{{~}}\n{{? pkList.length >0 }}\n PRIMARY KEY ({{~pkList:pkName:i}}{{= pkName }}{{= i0}}{{='('}}{{=field.len}}{{?field.scale>0}}{{=','}}{{=field.scale}}{{?}}{{=')'}}{{?}}{{= field.defaultValue ? it.func.join(' DEFAULT ',field.defaultValue,' ') : '' }}{{= field.notNull ? ' NOT NULL' : '' }}{{= field.autoIncrement ? '' : '' }}{{= index < it.entity.fields.length-1 ? ',' : ( pkList.length>0 ? ',' :'' ) }}\n{{~}}\n{{? pkList.length >0 }}\n PRIMARY KEY ({{~pkList:pkName:i}}{{= pkName }}{{= i0}}{{='('}}{{=field.len}}{{?field.scale>0}}{{=','}}{{=field.scale}}{{?}}{{=')'}}{{?}}{{= field.notNull ? ' NOT NULL' : '' }}{{= field.autoIncrement ? ' IDENTITY(1,1)' : '' }}{{= field.defaultValue ? it.func.join(' DEFAULT ',field.defaultValue,' ') : '' }}{{= index < it.entity.fields.length-1 ? ',' : ( pkList.length>0 ? ',' :'' ) }}\n{{~}}\n{{? pkList.length >0 }}\n PRIMARY KEY ({{~pkList:pkName:i}}{{= pkName }}{{= i0}}{{='('}}{{=field.len}}{{?field.scale>0}}{{=','}}{{=field.scale}}{{?}}{{=')'}}{{?}}{{= field.notNull ? ' NOT NULL' : '' }}{{= field.autoIncrement ? ' AUTO_INCREMENT' : '' }}{{= field.defaultValue ? it.func.join(' DEFAULT ',field.defaultValue,' ') : '' }}{{= index < it.entity.fields.length-1 ? ',' : ( pkList.length>0 ? ',' :'' ) }}\n{{~}}\n{{? pkList.length >0 }}\n PRIMARY KEY ({{~pkList:pkName:i}}{{= pkName }}{{= i0}}{{='('}}{{=field.len}}{{?field.scale>0}}{{=','}}{{=field.scale}}{{?}}{{=')'}}{{?}}{{= field.notNull ? ' NOT NULL' : '' }}{{= field.autoIncrement ? '' : '' }}{{= field.defaultValue ? it.func.join(' DEFAULT ',field.defaultValue,' ') : '' }}{{= index < it.entity.fields.length-1 ? ',' : ( pkList.length>0 ? ',' :'' ) }}\n{{~}}\n{{? pkList.length >0 }}\n PRIMARY KEY ({{~pkList:pkName:i}}{{= pkName }}{{= i0}}{{='('}}{{=field.len}}{{?field.scale>0}}{{=','}}{{=field.scale}}{{?}}{{=')'}}{{?}}{{= field.notNull ? ' NOT NULL' : '' }}{{= field.autoIncrement ? '' : '' }}{{= field.defaultValue ? it.func.join(' DEFAULT ','('+field.defaultValue+')',' ') : '' }}{{= index < it.entity.fields.length-1 ? ',' : ( pkList.length>0 ? ',' :'' ) }}\n{{~}}\n{{? pkList.length >0 }}\n PRIMARY KEY ({{~pkList:pkName:i}}{{= pkName }}{{= i\n /// {{=it.func.join(field.defName,field.comment,';')}}\n /// \n public {{=field.type}} {{=it.func.camel(field.defKey,true)}} { get; set; }\n $blankline\n {{~}}\n \n }\n}", + "apply": "F3AC2415-E86B-40C6-9FEB-F4B7937D2C30" + }, + { + "type": "dbDDL", + "applyFor": "753F434C-234D-47AD-804B-84D042F1AE32", + "isDefault": true, + "createTable": "DROP TABLE IF EXISTS {{=it.entity.defKey}};\nCREATE TABLE {{=it.entity.defKey}}(\n{{ pkList = [] ; }}\n{{~it.entity.fields:field:index}}\n {{? field.primaryKey }}{{ pkList.push(field.defKey) }}{{?}}\n {{=field.defKey}} {{=field.type}}{{?field.len>0}}{{='('}}{{=field.len}}{{?field.scale>0}}{{=','}}{{=field.scale}}{{?}}{{=')'}}{{?}}{{= field.notNull ? ' NOT NULL' : '' }}{{= field.autoIncrement ? ' AUTO_INCREMENT' : '' }}{{= field.defaultValue ? it.func.join(' DEFAULT ',field.defaultValue,' ') : '' }}{{= index < it.entity.fields.length-1 ? ',' : ( pkList.length>0 ? ',' :'' ) }}\n{{~}}\n{{? pkList.length >0 }}\n PRIMARY KEY ({{~pkList:pkName:i}}{{= pkName }}{{= i0}}{{='('}}{{=field.len}}{{?field.scale>0}}{{=','}}{{=field.scale}}{{?}}{{=')'}}{{= field.defaultValue ? it.func.join(' DEFAULT ',field.defaultValue,' ') : '' }}{{?}}{{= field.notNull ? ' NOT NULL' : '' }}{{= index < it.entity.fields.length-1 ? ',' : ( pkList.length>0 ? ',' :'' ) }}\n{{~}}\n{{? pkList.length >0 }}\n PRIMARY KEY ({{~pkList:pkName:i}}{{= pkName }}{{= i0 ? ',' :'' ) }}\n{{~}}\n{{? pkList.length >0 }}\n PRIMARY KEY ({{~pkList:pkName:i}}{{= pkName }}{{= i0}}{{='('}}{{=field.len}}{{?field.scale>0}}{{=','}}{{=field.scale}}{{?}}{{=')'}}{{?}} {{= field.notNull ? 'NOT NULL' : '' }} {{= field.autoIncrement ? 'AUTOINCREMENT' : '' }} {{= field.defaultValue ? it.func.join('DEFAULT',field.defaultValue,' ') : '' }}{{= index < it.entity.fields.length-1 ? ',' : ( pkList.length>0 ? ',' :'' ) }} --{{=it.func.join(field.defName,field.comment,';')}}\n{{~}}\n{{? pkList.length >0 }}\n PRIMARY KEY ({{~pkList:pkName:i}}{{= pkName }}{{= i", + "56F4B55B-F0B8-4049-9E6B-50B95C1D793A": "DATE", + "483F9346-C99E-4014-A1D2-A554606BD8A3": "DATETIME" + }, + { + "defKey": "bytes", + "id": "D516E75B-90F5-4741-B9B3-A186A263F04C", + "defName": "二进制", + "29D1CE08-4C35-4D2D-AAA9-23D93305B52E": "BLOB", + "A4E23CB7-BB01-4BD1-9F71-F73F3E15A542": "BLOB", + "BFC87171-C74F-494A-B7C2-76B9C55FACC9": "VARBINARY", + "DFBEC1DD-AA84-456E-BBF3-C95DD0DB2022": "BYTEA", + "89504F5D-94BF-4C9E-8B2E-44F37305FED5": "BLOB", + "0BBCABA5-B8E4-41B0-B8E4-8F5EA6029307": "BLOB", + "592C7013-143D-4E7B-AF64-0D7BF1E28230": "BYTEA", + "77BD85E5-9D0D-4096-8427-CBA306FC9C6A": "BYTEA", + "11D1FB71-A587-4217-89BA-611B8A1F83E0": "BINARY", + "B363BE0B-F852-49B8-9B2E-F6D2174DEAC1": "NONE", + "797A1496-D649-4261-89B4-544132EC3F36": "byte[]", + "895CFD1D-4273-4D32-A2C4-CAC70200AB5B": "byte[]", + "A2EE7B4A-CE62-4290-B00C-B26C1BF18073": "byte[]", + "F3AC2415-E86B-40C6-9FEB-F4B7937D2C30": "byte[]", + "81CCA482-3F4D-4EAC-8CF9-F5E7BC098AD2": "binary", + "B91D99E0-9B7C-416C-8737-B760957DAF09": "[]byte", + "56F4B55B-F0B8-4049-9E6B-50B95C1D793A": "BYTE" + }, + { + "defKey": "largeText", + "id": "B17BDED3-085F-40E1-9019-3B79CF2BF075", + "defName": "大文本", + "29D1CE08-4C35-4D2D-AAA9-23D93305B52E": "TEXT", + "A4E23CB7-BB01-4BD1-9F71-F73F3E15A542": "CLOB", + "BFC87171-C74F-494A-B7C2-76B9C55FACC9": "TEXT", + "DFBEC1DD-AA84-456E-BBF3-C95DD0DB2022": "TEXT", + "89504F5D-94BF-4C9E-8B2E-44F37305FED5": "CLOB", + "0BBCABA5-B8E4-41B0-B8E4-8F5EA6029307": "CLOB", + "592C7013-143D-4E7B-AF64-0D7BF1E28230": "TEXT", + "77BD85E5-9D0D-4096-8427-CBA306FC9C6A": "TEXT", + "11D1FB71-A587-4217-89BA-611B8A1F83E0": "STRING", + "B363BE0B-F852-49B8-9B2E-F6D2174DEAC1": "TEXT", + "797A1496-D649-4261-89B4-544132EC3F36": "String", + "895CFD1D-4273-4D32-A2C4-CAC70200AB5B": "String", + "A2EE7B4A-CE62-4290-B00C-B26C1BF18073": "String", + "F3AC2415-E86B-40C6-9FEB-F4B7937D2C30": "string", + "81CCA482-3F4D-4EAC-8CF9-F5E7BC098AD2": "string", + "B91D99E0-9B7C-416C-8737-B760957DAF09": "string", + "BDF457FD-9F98-4AC3-A705-7587B00A3BAB": "String", + "56F4B55B-F0B8-4049-9E6B-50B95C1D793A": "TEXT", + "483F9346-C99E-4014-A1D2-A554606BD8A3": "STRING" + }, + { + "defKey": "integer", + "id": "2F0597A0-B16A-4E91-AF8C-B28263544755", + "defName": "整数" + }, + { + "defKey": "long", + "id": "1A8A9C3C-15AC-43FC-8A1D-28B254CE103D", + "defName": "大整数", + "A4E23CB7-BB01-4BD1-9F71-F73F3E15A542": "Number" + } + ] + }, + "domains": [ + { + "defKey": "DefaultString", + "defName": "默认字串", + "applyFor": "FC9790A7-36B8-4A48-8F9A-BC1042BCFE64", + "len": 255, + "scale": "", + "uiHint": "", + "id": "9092C4E0-1A54-4859-ABBB-5B62DBC27573" + }, + { + "defKey": "IdOrKey", + "defName": "主键标识", + "applyFor": "FC9790A7-36B8-4A48-8F9A-BC1042BCFE64", + "len": 32, + "scale": "", + "uiHint": "", + "id": "16120F75-6AA7-4483-868D-F07F511BB081" + }, + { + "defKey": "Name", + "defName": "名称", + "applyFor": "FC9790A7-36B8-4A48-8F9A-BC1042BCFE64", + "len": 90, + "scale": "", + "uiHint": "", + "id": "54611CCC-CA4B-42E1-9F32-4944C85B85A6" + }, + { + "defKey": "Int", + "defName": "整数", + "applyFor": "1D764C4A-6F9F-421E-B11A-6F3E23B51811", + "len": "", + "scale": "", + "uiHint": "", + "id": "6BC8F04B-6CFA-4995-98D3-318F5CDD774E" + }, + { + "defKey": "Double", + "defName": "小数", + "applyFor": "1A0BDC09-0792-4174-9E8E-80BE8DF44B8E", + "len": 24, + "scale": 6, + "uiHint": "", + "id": "FF4459C5-6B45-4DBF-8FC0-E06239BC05B4" + }, + { + "defKey": "Money", + "defName": "金额", + "applyFor": "1A0BDC09-0792-4174-9E8E-80BE8DF44B8E", + "len": 24, + "scale": 6, + "uiHint": "", + "id": "C3B1681B-99F9-4818-9E80-DE1652A51D85" + }, + { + "defKey": "DateTime", + "defName": "日期时间", + "applyFor": "89D69E81-EA34-42EE-9FA2-93B8BD27E098", + "len": "", + "scale": "", + "uiHint": "", + "id": "7CFFA0D3-6A93-4DDC-BC10-DF21211064DC" + }, + { + "defKey": "YesNo", + "defName": "是否", + "applyFor": "FC9790A7-36B8-4A48-8F9A-BC1042BCFE64", + "len": "1", + "scale": "", + "uiHint": "", + "id": "6F7C1C5C-D159-41E6-BF9D-54DEEFA79AFF" + }, + { + "defKey": "Dict", + "defName": "数据字典", + "applyFor": "FC9790A7-36B8-4A48-8F9A-BC1042BCFE64", + "len": "32", + "scale": "", + "uiHint": "", + "id": "73FD2BAD-2358-4336-B96D-45DC897BD792" + }, + { + "defKey": "DescText", + "defName": "描述文本", + "applyFor": "FC9790A7-36B8-4A48-8F9A-BC1042BCFE64", + "len": "900", + "scale": "", + "uiHint": "", + "id": "3E948CEC-3070-472C-AF92-F3CA11EC9D15" + }, + { + "defKey": "LongKey", + "defName": "标识号-长_LongKey", + "applyFor": "FC9790A7-36B8-4A48-8F9A-BC1042BCFE64", + "len": 64, + "scale": "", + "id": "F0EBB769-5D6E-4EF3-99CA-DCC3AE69827E" + }, + { + "defKey": "Char", + "defName": "单字符_Char", + "applyFor": "FC9790A7-36B8-4A48-8F9A-BC1042BCFE64", + "len": 1, + "scale": "", + "id": "1BB9C8DC-8A10-414C-ABD5-6D621A6CFB98" + }, + { + "defKey": "Intro", + "defName": "备注说明_Intro", + "applyFor": "FC9790A7-36B8-4A48-8F9A-BC1042BCFE64", + "len": 512, + "scale": "", + "id": "BF1ADA67-474C-4017-8D4B-05F155FF935B" + }, + { + "defKey": "ShortString", + "defName": "字串-短_ShortString", + "applyFor": "FC9790A7-36B8-4A48-8F9A-BC1042BCFE64", + "len": 128, + "scale": "", + "id": "58F8E04A-5645-445E-AFC7-5DB5110049BF" + }, + { + "defKey": "MiddleString", + "defName": "字串-中_MiddleString", + "applyFor": "FC9790A7-36B8-4A48-8F9A-BC1042BCFE64", + "len": 1024, + "scale": "", + "id": "6F67EBAF-9B16-474C-840A-85EF33578E79" + }, + { + "defKey": "LongString", + "defName": "字串-长_LongString", + "applyFor": "FC9790A7-36B8-4A48-8F9A-BC1042BCFE64", + "len": 2, + "scale": "", + "id": "01BA1028-4597-45C3-A43B-9600794C8E76" + }, + { + "defKey": "LongText", + "defName": "大文本_LongText", + "applyFor": "FC9790A7-36B8-4A48-8F9A-BC1042BCFE64", + "len": 4000, + "scale": "", + "id": "C4848B19-D0A0-4A40-AE63-27BE0DF15937" + }, + { + "defKey": "Ratio", + "defName": "比例_Ratio", + "applyFor": "1A0BDC09-0792-4174-9E8E-80BE8DF44B8E", + "len": 4, + "scale": 2, + "id": "10B975C9-8342-4A0C-B5B4-856915FFC90F" + }, + { + "defKey": "Integer", + "defName": "整数_Integer", + "applyFor": "2F0597A0-B16A-4E91-AF8C-B28263544755", + "len": "", + "scale": "", + "id": "14F40377-4BA8-4E33-B15A-54770BDDE761" + }, + { + "defKey": "BigInt", + "defName": "大整数_BigInt", + "applyFor": "1A8A9C3C-15AC-43FC-8A1D-28B254CE103D", + "len": "", + "scale": "", + "id": "1AF3C2A2-F8ED-4D89-8EB9-E8D93C8B7698" + }, + { + "defKey": "Date", + "defName": "日期_Date", + "applyFor": "", + "len": "", + "scale": "", + "id": "EF221659-DBCF-4F59-AA6A-D635D44460D8" + }, + { + "defKey": "var20", + "defName": "20字符_var20", + "applyFor": "FC9790A7-36B8-4A48-8F9A-BC1042BCFE64", + "len": 20, + "scale": "", + "id": "05781CAE-BE28-48B8-B70C-9E61E31F272E" + }, + { + "defKey": "var36", + "defName": "36字符_va36", + "applyFor": "FC9790A7-36B8-4A48-8F9A-BC1042BCFE64", + "len": 36, + "scale": "", + "id": "518EFC41-B8E8-4CCC-AA5B-1CCA608BF5F4" + } + ], + "diagrams": [], + "standardFields": [ + { + "defKey": "personInfo", + "defName": "个人基本信息要素", + "fields": [ + { + "defKey": "ID_CARD_NO", + "defName": "身份证号", + "comment": "", + "type": "VARCHAR", + "len": "60", + "scale": "", + "primaryKey": false, + "notNull": false, + "autoIncrement": false, + "defaultValue": "", + "hideInGraph": false, + "domain": "9092C4E0-1A54-4859-ABBB-5B62DBC27573", + "refDict": "", + "uiHint": "", + "id": "A64A91C8-A41F-4113-92FB-7563D7EF054D" + }, + { + "defKey": "MOBILE_PHONE", + "defName": "手机号", + "comment": "", + "type": "VARCHAR", + "len": "60", + "scale": "", + "primaryKey": false, + "notNull": false, + "autoIncrement": false, + "defaultValue": "", + "hideInGraph": false, + "domain": "9092C4E0-1A54-4859-ABBB-5B62DBC27573", + "refDict": "", + "uiHint": "", + "id": "479DA2AB-1974-411A-A81E-92FB939E75EB" + }, + { + "defKey": "GENDER", + "defName": "性别", + "comment": "", + "type": "VARCHAR", + "len": "32", + "scale": "", + "primaryKey": false, + "notNull": false, + "autoIncrement": false, + "defaultValue": "", + "hideInGraph": false, + "domain": "73FD2BAD-2358-4336-B96D-45DC897BD792", + "refDict": "BF9E20E0-80D3-486D-BD58-5FADCF3E4A1D", + "uiHint": "", + "id": "48473E29-6594-4912-AADE-C8AB44FCA3E9" + }, + { + "defKey": "BIRTH", + "defName": "出生日期", + "comment": "", + "type": "DATETIME", + "len": "", + "scale": "", + "primaryKey": false, + "notNull": false, + "autoIncrement": false, + "defaultValue": "", + "hideInGraph": false, + "domain": "7CFFA0D3-6A93-4DDC-BC10-DF21211064DC", + "refDict": "", + "uiHint": "", + "id": "2BD3D2EE-2411-49A6-983D-84B81057312F" + }, + { + "defKey": "AVATAR", + "defName": "头像", + "comment": "", + "type": "VARCHAR", + "len": "60", + "scale": "", + "primaryKey": false, + "notNull": false, + "autoIncrement": false, + "defaultValue": "", + "hideInGraph": false, + "domain": "9092C4E0-1A54-4859-ABBB-5B62DBC27573", + "refDict": "", + "uiHint": "", + "id": "FDD67CEE-4B52-4BD1-A1A3-9C5EBC6037E6" + }, + { + "defKey": "HEIGHT", + "defName": "身高", + "comment": "", + "type": "INT", + "len": "", + "scale": "", + "primaryKey": false, + "notNull": false, + "autoIncrement": false, + "defaultValue": "", + "hideInGraph": false, + "domain": "6BC8F04B-6CFA-4995-98D3-318F5CDD774E", + "refDict": "", + "uiHint": "", + "id": "CAAA0E79-41A1-4758-B481-D171168C4D68" + }, + { + "defKey": "WEIGHT", + "defName": "体重", + "comment": "", + "type": "INT", + "len": "", + "scale": "", + "primaryKey": false, + "notNull": false, + "autoIncrement": false, + "defaultValue": "", + "hideInGraph": false, + "domain": "6BC8F04B-6CFA-4995-98D3-318F5CDD774E", + "refDict": "", + "uiHint": "", + "id": "575482CE-64A6-4CB9-99DC-8E126D190AAA" + }, + { + "defKey": "NATION", + "defName": "名族", + "comment": "", + "type": "VARCHAR", + "len": "32", + "scale": "", + "primaryKey": false, + "notNull": false, + "autoIncrement": false, + "defaultValue": "", + "hideInGraph": false, + "domain": "73FD2BAD-2358-4336-B96D-45DC897BD792", + "refDict": "115EDEFC-0323-410E-81AB-CCAB8879837A", + "uiHint": "", + "id": "15B0D75D-0B97-4985-A816-D0EAFA90446B" + }, + { + "defKey": "POLITICAL", + "defName": "政治面貌", + "comment": "", + "type": "VARCHAR", + "len": "32", + "scale": "", + "primaryKey": false, + "notNull": false, + "autoIncrement": false, + "defaultValue": "", + "hideInGraph": false, + "domain": "73FD2BAD-2358-4336-B96D-45DC897BD792", + "refDict": "06EED564-BBA9-4747-8D73-AF809A330CB8", + "uiHint": "", + "id": "F458E86D-84D6-45A1-9DD3-51E6C8170D7F" + }, + { + "defKey": "MARITAL", + "defName": "婚姻状况", + "comment": "", + "type": "VARCHAR", + "len": "32", + "scale": "", + "primaryKey": false, + "notNull": false, + "autoIncrement": false, + "defaultValue": "", + "hideInGraph": false, + "domain": "73FD2BAD-2358-4336-B96D-45DC897BD792", + "refDict": "EA1587B7-3954-437A-BFE0-FCB0453BCABA", + "uiHint": "", + "id": "7275E578-6893-4922-AC69-95B261BFBD61" + }, + { + "defKey": "DOMICILE_PLACE_PROVINCE", + "defName": "籍贯(省)", + "comment": "", + "type": "VARCHAR", + "len": "60", + "scale": "", + "primaryKey": false, + "notNull": false, + "autoIncrement": false, + "defaultValue": "", + "hideInGraph": false, + "domain": "9092C4E0-1A54-4859-ABBB-5B62DBC27573", + "refDict": "", + "uiHint": "", + "id": "F04BF130-3EC1-4E02-9DED-3214CA88E352" + }, + { + "defKey": "DOMICILE_PLACE_CITY", + "defName": "籍贯(市)", + "comment": "", + "type": "VARCHAR", + "len": "32", + "scale": "", + "primaryKey": false, + "notNull": false, + "autoIncrement": false, + "defaultValue": "", + "hideInGraph": false, + "domain": "73FD2BAD-2358-4336-B96D-45DC897BD792", + "refDict": "", + "uiHint": "", + "id": "B97F5BC2-33DE-4857-9DB8-ECFD02C9040C" + }, + { + "defKey": "DOMICILE_PLACE_ADDRESS", + "defName": "户籍地址", + "comment": "", + "type": "VARCHAR", + "len": "60", + "scale": "", + "primaryKey": false, + "notNull": false, + "autoIncrement": false, + "defaultValue": "", + "hideInGraph": false, + "domain": "9092C4E0-1A54-4859-ABBB-5B62DBC27573", + "refDict": "", + "uiHint": "", + "id": "812ADF1D-8C03-40CA-B030-E539838FB889" + } + ], + "id": "F30202B9-4B5D-4CE7-87CE-B3890C84D3F2" + } + ], + "dbConn": [] +} \ No newline at end of file diff --git a/db/加入网办入口.sql b/db/加入网办入口.sql new file mode 100644 index 0000000..0f67e52 --- /dev/null +++ b/db/加入网办入口.sql @@ -0,0 +1,5 @@ +ALTER TABLE "DEVOPS"."REPAIR_TODO" + MODIFY ("SOURCE" VARCHAR2(10 BYTE)); +COMMENT ON COLUMN "DEVOPS"."REPAIR_TODO"."SOURCE" IS '报障单来源;1:内网、2:特设系统外网'; + +UPDATE "DEVOPS"."REPAIR_TODO" SET "SOURCE" = '1'; \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..37bad34 --- /dev/null +++ b/pom.xml @@ -0,0 +1,156 @@ + + + + 4.0.0 + + com.chinaweal.youfool + youfool-devops + 1.0.0-SNAPSHOT + war + + youfool-devops + https://www.chinaweal.com.cn + + org.springframework.boot + spring-boot-starter-parent + 2.2.6.RELEASE + + + + 1.8 + true + 2.17.1 + 1.2.9 + 1.12.0 + + + + + com.chinaweal.youfool + youfool-framework-springboot + 1.1.1-SNAPSHOT + + + org.apache.logging.log4j + log4j-api + + + org.apache.logging.log4j + log4j-to-slf4j + + + org.apache.shiro + shiro-spring + + + + + + com.alibaba + druid-spring-boot-starter + 1.1.21 + + + + org.projectlombok + lombok + 1.18.12 + provided + + + com.dtflys.forest + forest-spring-boot-starter + 1.5.16 + + + + cn.hutool + hutool-all + 5.3.7 + + + + com.oracle.ojdbc + ojdbc8 + 19.3.0.0 + + + + cn.easyproject + orai18n + 12.1.0.2.0 + + + junit + junit + 4.12 + test + + + com.alibaba + easyexcel + 2.2.6 + + + javax.websocket + javax.websocket-api + 1.1 + provided + + + + net.coobird + thumbnailator + 0.4.14 + + + + e-iceblue + spire.xls + 3.9.1 + + + + org.apache.logging.log4j + log4j-api + ${log4j.version} + + + org.apache.logging.log4j + log4j-to-slf4j + ${log4j.version} + + + + ch.qos.logback + logback-core + ${logback.version} + + + ch.qos.logback + logback-classic + ${logback.version} + + + + org.mybatis + mybatis + 3.5.6 + + + + org.apache.shiro + shiro-spring + ${shiro.version} + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/src/main/java/com/chinaweal/youfool/devops/DevOpsApplication.java b/src/main/java/com/chinaweal/youfool/devops/DevOpsApplication.java new file mode 100644 index 0000000..9f9b1a8 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/DevOpsApplication.java @@ -0,0 +1,45 @@ +package com.chinaweal.youfool.devops; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.scheduling.annotation.EnableScheduling; + +@SpringBootApplication(scanBasePackages = {"com.chinaweal"}) +@Slf4j +@EnableScheduling +public class DevOpsApplication extends SpringBootServletInitializer implements ApplicationListener { + @Value("${applicationName}") + private String applicationName; + @Value("${version}") + private String version; + @Value("${description}") + private String description; + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder applicationBuilder) { + return applicationBuilder.sources(DevOpsApplication.class); + } + + @Override + public void onApplicationEvent(ContextRefreshedEvent event) { + if (event.getApplicationContext().getParent() == null) { + log.info("========================== 程序启动成功! =========================="); + log.info("====== 程 序:{} !", applicationName); + log.info("====== 版本号:{} ", version); + log.info("====== 描 述:{} ", description); + log.info("====== 接口文档路径:/doc.html,账号:admin、密码:123456。注:如果乱码请指定VM -Dfile.encoding=UTF-8"); + log.info("====== Druid Monitor路径:/druid,账号:admin、密码:123456"); + log.info("===================================================================="); + } + } + + public static void main(String[] args) { + SpringApplication.run(DevOpsApplication.class, args); + } +} diff --git a/src/main/java/com/chinaweal/youfool/devops/base/controller/DictController.java b/src/main/java/com/chinaweal/youfool/devops/base/controller/DictController.java new file mode 100644 index 0000000..70cb8ee --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/base/controller/DictController.java @@ -0,0 +1,72 @@ +package com.chinaweal.youfool.devops.base.controller; + + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.chinaweal.youfool.devops.base.entity.Dict; +import com.chinaweal.youfool.devops.base.service.IDictService; +import com.chinaweal.youfool.framework.springboot.base.query.BaseQuery; +import com.chinaweal.youfool.framework.springboot.rest.RestResult; +import com.github.xiaoymin.knife4j.annotations.ApiSort; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + *

+ * 字典 前端控制器 + *

+ * + * @author chinaweal + * @since 2020-07-07 + */ +@Api(tags = "1.字典") +@ApiSort(1) +@RestController("devopsDictController") +@RequestMapping("/dict") +public class DictController { + + @Resource + private IDictService iDictService; + + @GetMapping + @ApiImplicitParam(name = "type", value = "类型", required = true) + @ApiOperation(value = "1.根据类型查询字典列表", position = 1) + public RestResult> listByType(@RequestParam String type) { + List list = iDictService.listByType(type); + return RestResult.ok(list); + } + + @ApiOperation(value = "2.字典分类列表", position = 2) + @PostMapping("/list") + public RestResult> list(@RequestBody BaseQuery query) { + IPage data = iDictService.list(query); + return RestResult.ok(data); + } + + @ApiOperation(value = "3.修改字典", position = 3) + @PostMapping("/update") + public RestResult updateDict(@RequestBody Dict dict) { + iDictService.updateById(dict); + return RestResult.ok(); + } + + @ApiOperation(value = "4.删除字典", position = 4) + @DeleteMapping + public RestResult deleteDict(@RequestParam @ApiParam("字典ID") String dictId) { + iDictService.removeById(dictId); + return RestResult.ok(); + } + + @ApiOperation(value = "5.新增字典", position = 5) + @PostMapping + public RestResult saveDict(@RequestBody Dict dict) { + iDictService.save(dict); + return RestResult.ok(); + } +} diff --git a/src/main/java/com/chinaweal/youfool/devops/base/controller/TaskFileController.java b/src/main/java/com/chinaweal/youfool/devops/base/controller/TaskFileController.java new file mode 100644 index 0000000..06be087 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/base/controller/TaskFileController.java @@ -0,0 +1,60 @@ +package com.chinaweal.youfool.devops.base.controller; + +import com.chinaweal.youfool.devops.base.service.ITaskFileService; +import com.chinaweal.youfool.framework.springboot.rest.RestResult; +import com.github.xiaoymin.knife4j.annotations.ApiSort; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Map; + +/** + *

+ * 任务附件 控制器 + *

+ * + * @author chinaweal + * @since 2022-03-17 + */ +@Api(tags = "任务附件") +@ApiSort(1) +@RestController +@RequestMapping("/base/taskFile") +public class TaskFileController { + + @Resource + private ITaskFileService iTaskFileService; + + @ApiOperation(value = "1.上传附件", position = 1) + @PostMapping("/uploadFile") + public RestResult> uploadFile(MultipartFile file, @RequestParam String taskId, + @RequestParam(required = false) String handleId, @RequestParam String type) throws IOException { + Map body = iTaskFileService.updateFile(file, taskId, type, handleId); + return RestResult.ok(body); + } + + @ApiOperation(value = "2.删除文件", position = 2) + @GetMapping("/deleteFile") + public RestResult deleteFile(@RequestParam String id) { + iTaskFileService.deleteFile(id); + return RestResult.ok(); + } + + @ApiOperation(value = "3.文件下载", position = 3) + @GetMapping(value = "/downloadFile", produces = "application/octet-stream") + @ApiImplicitParams({ + @ApiImplicitParam(name = "id", value = "文件ID", required = true), + @ApiImplicitParam(name = "online", value = "是否在线预览;true:在线、false:直接下载") + }) + public void downloadFile(@RequestParam String id, @RequestParam(defaultValue = "true") boolean online, HttpServletResponse response) throws IOException { + iTaskFileService.downloadFile(id, online, response); + } + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/base/controller/TaskHandleController.java b/src/main/java/com/chinaweal/youfool/devops/base/controller/TaskHandleController.java new file mode 100644 index 0000000..3508f0f --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/base/controller/TaskHandleController.java @@ -0,0 +1,31 @@ +package com.chinaweal.youfool.devops.base.controller; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.chinaweal.youfool.devops.base.entity.TaskHandle; +import com.chinaweal.youfool.devops.base.service.ITaskHandleService; +import com.chinaweal.youfool.framework.springboot.base.query.BaseQuery; +import com.chinaweal.youfool.framework.springboot.rest.RestResult; +import com.github.xiaoymin.knife4j.annotations.ApiSort; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.io.Serializable; + +/** + *

+ * 任务处理流程记录 控制器 + *

+ * + * @author chinaweal + * @since 2022-03-17 + */ +@Api(tags = "任务处理流程记录") +@ApiSort(1) +@RestController +@RequestMapping("/base/taskHandle") +public class TaskHandleController { + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/base/controller/TaskListController.java b/src/main/java/com/chinaweal/youfool/devops/base/controller/TaskListController.java new file mode 100644 index 0000000..1bf4b71 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/base/controller/TaskListController.java @@ -0,0 +1,33 @@ +package com.chinaweal.youfool.devops.base.controller; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.chinaweal.youfool.devops.base.entity.TaskList; +import com.chinaweal.youfool.devops.base.service.ITaskListService; +import com.chinaweal.youfool.framework.springboot.base.query.BaseQuery; +import com.chinaweal.youfool.framework.springboot.rest.RestResult; +import com.github.xiaoymin.knife4j.annotations.ApiSort; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +/** + *

+ * 待办表 控制器 + *

+ * + * @author chinaweal + * @since 2022-03-17 + */ +@Api(tags = "待办表") +@ApiSort(1) +@RestController +@RequestMapping("/base/taskList") +public class TaskListController { + + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/base/controller/query/BaseListQuery.java b/src/main/java/com/chinaweal/youfool/devops/base/controller/query/BaseListQuery.java new file mode 100644 index 0000000..70a9c72 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/base/controller/query/BaseListQuery.java @@ -0,0 +1,33 @@ +package com.chinaweal.youfool.devops.base.controller.query; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +/** + * 分页查询参数父类 + */ +@ApiModel("列表参数父类") +@Data +public class BaseListQuery { + + @ApiModelProperty(value = "创建开始时间", dataType = "localDateTime") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createStart; + @ApiModelProperty(value = "创建结束时间", dataType = "localDateTime") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createEnd; + + @ApiModelProperty(value = "排序字段") + private String orderField; + @ApiModelProperty(value = "排序规则;asc:升序;desc:降序") + private String orderSort = "asc"; + + @ApiModelProperty(value = "当前页", dataType = "int") + private int current = 1; + @ApiModelProperty(value = "每页显示条数", dataType = "int") + private int size = 10; +} diff --git a/src/main/java/com/chinaweal/youfool/devops/base/entity/Dict.java b/src/main/java/com/chinaweal/youfool/devops/base/entity/Dict.java new file mode 100644 index 0000000..9af6189 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/base/entity/Dict.java @@ -0,0 +1,68 @@ +package com.chinaweal.youfool.devops.base.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableField; +import com.chinaweal.youfool.framework.springboot.mybatis.plus.SuperEntity; +import com.chinaweal.youfool.framework.springboot.json.LocalDateTimeStringSerializer; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + *

+ * 字典 + *

+ * + * @author chinaweal + * @since 2020-07-07 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +@TableName("DICT") +@ApiModel(value = "Dict对象", description = "字典") +public class Dict extends SuperEntity { + + private static final long serialVersionUID = 1L; + + /** + * 字典ID + */ + @ApiModelProperty(value = "字典ID") + @TableId(value = "DICT_ID", type = IdType.ASSIGN_UUID) + private String dictId; + + /** + * 类型 + */ + @ApiModelProperty(value = "类型") + @TableField("TYPE") + private String type; + + /** + * 代码 + */ + @ApiModelProperty(value = "代码") + @TableField("CODE") + private String code; + + /** + * 名称 + */ + @ApiModelProperty(value = "名称") + @TableField("NAME") + private String name; + /** + * 排序 + */ + @ApiModelProperty(value = "排序") + @TableField("SORT") + private String sort; + + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/base/entity/TaskFile.java b/src/main/java/com/chinaweal/youfool/devops/base/entity/TaskFile.java new file mode 100644 index 0000000..ad1dcd1 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/base/entity/TaskFile.java @@ -0,0 +1,101 @@ +package com.chinaweal.youfool.devops.base.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.chinaweal.youfool.framework.springboot.json.LocalDateTimeStringSerializer; +import com.chinaweal.youfool.framework.springboot.mybatis.plus.SuperEntity; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + *

+ * 任务附件 + *

+ * + * @author chinaweal + * @since 2022-03-17 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +@TableName("TASK_FILE") +@ApiModel(value = "TaskFile对象", description = "任务附件") +public class TaskFile extends SuperEntity { + + private static final long serialVersionUID = 1L; + + /** + * 文件ID + */ + @ApiModelProperty(value = "文件ID") + @TableId(value = "ID", type = IdType.ASSIGN_UUID) + private String id; + + /** + * 文件名 + */ + @ApiModelProperty(value = "文件名") + @TableField("FILE_NAME") + private String fileName; + + /** + * 文件类型 + */ + @ApiModelProperty(value = "文件类型") + @TableField("FILE_TYPE") + private String fileType; + + /** + * 类型 + */ + @ApiModelProperty(value = "类型") + @TableField("TYPE") + private String type; + + /** + * 文件路径 + */ + @ApiModelProperty(value = "文件路径") + @TableField("FILE_PATH") + private String filePath; + + /** + * 文件大小;单位字节 + */ + @ApiModelProperty(value = "文件大小;单位字节") + @TableField("FILE_SIZE") + private Long fileSize; + + /** + * 待办id + */ + @ApiModelProperty(value = "待办id") + @TableField("TASK_ID") + private String taskId; + + /** + * 处理ID;对处理流程记录 + */ + @ApiModelProperty(value = "处理ID;对处理流程记录") + @TableField("HANDLE_ID") + private String handleId; + + /** + * 上传时间 + */ + @ApiModelProperty(value = "上传时间") + @TableField("UPLOAD_TIME") + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime uploadTime; + + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/base/entity/TaskHandle.java b/src/main/java/com/chinaweal/youfool/devops/base/entity/TaskHandle.java new file mode 100644 index 0000000..a9170b7 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/base/entity/TaskHandle.java @@ -0,0 +1,139 @@ +package com.chinaweal.youfool.devops.base.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.chinaweal.youfool.framework.springboot.json.LocalDateTimeStringSerializer; +import com.chinaweal.youfool.framework.springboot.mybatis.plus.SuperEntity; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +/** + *

+ * 任务处理流程记录 + *

+ * + * @author chinaweal + * @since 2022-03-17 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +@TableName("TASK_HANDLE") +@ApiModel(value = "TaskHandle对象", description = "任务处理流程记录") +public class TaskHandle extends SuperEntity { + + private static final long serialVersionUID = 1L; + + /** + * 处理ID + */ + @ApiModelProperty(value = "处理ID") + @TableId(value = "HANDLE_ID", type = IdType.ASSIGN_UUID) + private String handleId; + + /** + * 待办id + */ + @ApiModelProperty(value = "待办id") + @TableField("TASK_ID") + private String taskId; + + /** + * 类型 + */ + @ApiModelProperty(value = "类型") + @TableField("BUS_TYPE") + private String busType; + + /** + * 处理人 + */ + @ApiModelProperty(value = "处理人") + @TableField("HANDLE_NICKNAME") + private String handleNickname; + + /** + * 处理人ID + */ + @ApiModelProperty(value = "处理人ID") + @TableField("HANDLE_USER_ID") + private String handleUserId; + + /** + * 处理人账号 + */ + @ApiModelProperty(value = "处理人账号") + @TableField("HANDLE_USERNAME") + private String handleUsername; + + /** + * 环节步骤;start:开始;assign:分派;handle:处理中;feedback:已反馈;unresolved:未解决;end:结束; + */ + @ApiModelProperty(value = "环节步骤;start:开始;assign:分派;handle:处理中;feedback:已反馈;unresolved:未解决;end:结束;") + @TableField("STEP") + private String step; + + @ApiModelProperty(value = "步骤次数") + @TableField("ORDER_INDEX") + private Integer orderIndex; + + /** + * 生成时间 + */ + @ApiModelProperty(value = "生成时间") + @TableField("HAPPEN_TIME") + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime happenTime; + + /** + * 处理结果 + */ + @ApiModelProperty(value = "处理结果") + @TableField("RESULT") + private String result; + + /** + * 环节状态;0:过期;1:有效 + */ + @ApiModelProperty(value = "环节状态;0:过期;1:有效") + @TableField("STATUS") + private String status; + + @TableField(exist = false) + private List files = new ArrayList<>(); + + + /** + * 下一个节点表单 + */ + @TableField(exist = false) + private String nextStep; + + /** + * 下一个步处理人用户 + */ + @TableField(exist = false) + private String nextHandleUsername; + + /** + * 下一个步处理人用户id + */ + @TableField(exist = false) + private String nextHandleUserId; + + /** + * 下一个步处理人名 + */ + @TableField(exist = false) + private String nextHandleNickname; +} diff --git a/src/main/java/com/chinaweal/youfool/devops/base/entity/TaskList.java b/src/main/java/com/chinaweal/youfool/devops/base/entity/TaskList.java new file mode 100644 index 0000000..c58b85f --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/base/entity/TaskList.java @@ -0,0 +1,198 @@ +package com.chinaweal.youfool.devops.base.entity; + +import com.baomidou.mybatisplus.annotation.*; +import com.chinaweal.youfool.framework.springboot.json.LocalDateTimeStringSerializer; +import com.chinaweal.youfool.framework.springboot.mybatis.plus.SuperEntity; +import com.chinaweal.youfool.framework.springboot.util.ConstantsUtil; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; + +/** + *

+ * 待办表 + *

+ * + * @author chinaweal + * @since 2022-03-17 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +@TableName("TASK_LIST") +@ApiModel(value = "TaskList对象", description = "待办表") +public class TaskList extends SuperEntity { + + private static final long serialVersionUID = 1L; + + /** + * 待办ID + */ + @ApiModelProperty(value = "待办ID") + @TableId(value = "task_id", type = IdType.ASSIGN_UUID) + private String taskId; + + /** + * 业务表ID,对应业务的表的ID + */ + @ApiModelProperty(value = "业务表ID,对应业务的表的ID") + @TableField("BIZ_ID") + private String bizId; + + /** + * 标题 + */ + @ApiModelProperty(value = "标题") + @TableField("TITLE") + private String title; + + /** + * 申报账号ID + */ + @ApiModelProperty(value = "申报账号ID") + @TableField("SEND_ID") + private String sendId; + + /** + * 申报用户昵称 + */ + @ApiModelProperty(value = "申报用户昵称") + @TableField("SEND_NAME") + private String sendName; + + /** + * 申报用户账号 + */ + @ApiModelProperty(value = "申报用户账号") + @TableField("SEND_USERNAME") + private String sendUsername; + + /** + * 签收人ID,个人或机构 + */ + @ApiModelProperty(value = "签收人ID,个人或机构") + @TableField("SIGN_ID") + private String signId; + + /** + * 签收人账号,个人或机构 + */ + @ApiModelProperty(value = "签收人账号,个人或机构") + @TableField("SIGN_USERNAME") + private String signUsername; + + /** + * 签收人名称 + */ + @ApiModelProperty(value = "签收人名称") + @TableField("SIGN_NAME") + private String signName; + + /** + * 所属机构Id + */ + @ApiModelProperty(value = "所属机构Id") + @TableField("ORG_ID") + private String orgId; + + /** + * 所属机构 + */ + @ApiModelProperty(value = "所属机构") + @TableField("ORG") + private String org; + + /** + * 所属部门Id + */ + @ApiModelProperty(value = "所属部门Id") + @TableField("DEPT_ID") + private String deptId; + + /** + * 所属部门 + */ + @ApiModelProperty(value = "所属部门") + @TableField("DEPT") + private String dept; + + /** + * 业务类型;assign:领导交办 + */ + @ApiModelProperty(value = "业务类型;assign:领导交办") + @TableField("BUS_TYPE") + private String busType; + + /** + * 优先级别;1:紧急;2:高;3:中;4:低 + */ + @ApiModelProperty(value = "优先级别;1:紧急;2:高;3:中;4:低") + @TableField("PRIORITY") + private Integer priority; + + /** + * 紧急程度;1:紧急;2:高;3:中;4:低 + */ + @ApiModelProperty(value = "紧急程度;1:紧急;2:高;3:中;4:低") + @TableField("URGENCY") + private Integer urgency; + + /** + * 环节步骤; + */ + @ApiModelProperty(value = "环节步骤;") + @TableField("STEP") + private String step; + + /** + * 催单次数 + */ + @ApiModelProperty(value = "催单次数") + @TableField("REMINDER") + private Integer reminder; + + /** + * 是否删除;0:有效;1:删除 + */ + @ApiModelProperty(value = "是否删除;0:有效;1:删除") + @TableField("DELETED") + @TableLogic(value = ConstantsUtil.NOT_DELETED, delval = ConstantsUtil.DELETED) + private String deleted; + + /** + * 报送时间 + */ + @ApiModelProperty(value = "报送时间") + @TableField("LAUNCH_TIME") + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime launchTime; + + /** + * 到期时间 + */ + @ApiModelProperty(value = "到期时间") + @TableField("SOLVE_LIMIT_TIME") + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime solveLimitTime; + + /** + * 处理更新时间 + */ + @ApiModelProperty(value = "处理更新时间") + @TableField("HANDLE_TIME") + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime handleTime; + + /** + * 任务状态 0:在办;1:办结; + */ + @ApiModelProperty(value = "任务状态 0:在办;1:办结;") + @TableField("status") + private String status; + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/base/mapper/DictMapper.java b/src/main/java/com/chinaweal/youfool/devops/base/mapper/DictMapper.java new file mode 100644 index 0000000..e6e7f58 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/base/mapper/DictMapper.java @@ -0,0 +1,18 @@ +package com.chinaweal.youfool.devops.base.mapper; + +import com.chinaweal.youfool.devops.base.entity.Dict; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.springframework.stereotype.Repository; + +/** + *

+ * 字典 Mapper 接口 + *

+ * + * @author chinaweal + * @since 2020-07-07 + */ +@Repository("devopsDictMapper") +public interface DictMapper extends BaseMapper { + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/base/mapper/TaskFileMapper.java b/src/main/java/com/chinaweal/youfool/devops/base/mapper/TaskFileMapper.java new file mode 100644 index 0000000..42a9a05 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/base/mapper/TaskFileMapper.java @@ -0,0 +1,16 @@ +package com.chinaweal.youfool.devops.base.mapper; + +import com.chinaweal.youfool.devops.base.entity.TaskFile; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * 任务附件 Mapper 接口 + *

+ * + * @author chinaweal + * @since 2022-03-17 + */ +public interface TaskFileMapper extends BaseMapper { + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/base/mapper/TaskHandleMapper.java b/src/main/java/com/chinaweal/youfool/devops/base/mapper/TaskHandleMapper.java new file mode 100644 index 0000000..8fc6c04 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/base/mapper/TaskHandleMapper.java @@ -0,0 +1,21 @@ +package com.chinaweal.youfool.devops.base.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.chinaweal.youfool.devops.base.entity.TaskHandle; +import org.apache.ibatis.annotations.Param; + +/** + *

+ * 任务处理流程记录 Mapper 接口 + *

+ * + * @author chinaweal + * @since 2022-03-17 + */ +public interface TaskHandleMapper extends BaseMapper { + + /** + * 根据bizId,查询最大的orderIndex值 + */ + Long maxOrderIndex(@Param("taskId") String taskId); +} diff --git a/src/main/java/com/chinaweal/youfool/devops/base/mapper/TaskListMapper.java b/src/main/java/com/chinaweal/youfool/devops/base/mapper/TaskListMapper.java new file mode 100644 index 0000000..6c151b5 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/base/mapper/TaskListMapper.java @@ -0,0 +1,16 @@ +package com.chinaweal.youfool.devops.base.mapper; + +import com.chinaweal.youfool.devops.base.entity.TaskList; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * 待办表 Mapper 接口 + *

+ * + * @author chinaweal + * @since 2022-03-17 + */ +public interface TaskListMapper extends BaseMapper { + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/base/service/IDictService.java b/src/main/java/com/chinaweal/youfool/devops/base/service/IDictService.java new file mode 100644 index 0000000..2d98a54 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/base/service/IDictService.java @@ -0,0 +1,35 @@ +package com.chinaweal.youfool.devops.base.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.chinaweal.youfool.devops.base.entity.Dict; +import com.chinaweal.youfool.framework.springboot.base.query.BaseQuery; + +import java.util.List; + +/** + *

+ * 字典 服务类 + *

+ * + * @author chinaweal + * @since 2020-07-07 + */ +public interface IDictService extends IService { + + String LABEL = "label"; + + String QUESTION = "question"; + + String ASSIGN_EVENT_TYPE = "assignEventType"; + + List listByType(String type); + + Dict getByTypeAndCode(String type, String code); + + void saveNameByTypeCode(String type, String code, String name); + + IPage list(BaseQuery query); + + void addDict(String type,String name); +} diff --git a/src/main/java/com/chinaweal/youfool/devops/base/service/IMonitorService.java b/src/main/java/com/chinaweal/youfool/devops/base/service/IMonitorService.java new file mode 100644 index 0000000..1bc7092 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/base/service/IMonitorService.java @@ -0,0 +1,14 @@ +package com.chinaweal.youfool.devops.base.service; + +/** + * 自定义运维监控,例如密码过期监控 + */ +public interface IMonitorService { + + + /** + * 查询数据库密码过期情况 + */ + void countDbPwdExpireAndSendWx() throws Exception; + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/base/service/ITaskFileService.java b/src/main/java/com/chinaweal/youfool/devops/base/service/ITaskFileService.java new file mode 100644 index 0000000..36e2027 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/base/service/ITaskFileService.java @@ -0,0 +1,43 @@ +package com.chinaweal.youfool.devops.base.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.chinaweal.youfool.devops.base.entity.TaskFile; +import com.chinaweal.youfool.framework.springboot.base.query.BaseQuery; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +/** + *

+ * 任务附件 服务类 + *

+ * + * @author chinaweal + * @since 2022-03-17 + */ +public interface ITaskFileService extends IService { + + /** + * 分页查询任务附件 + */ + IPage listTaskFile(BaseQuery query); + + Map updateFile(MultipartFile file, String bizId, String type, String handleId) throws IOException; + + /** + * 获取上传保存相对目录,格式:类型 + 当天的日期 + */ + String filePath(String type); + + void deleteFile(String id); + + List listByTaskIdAndType(String taskId, String type); + + List listByHandleId(String handleId); + + void downloadFile(String id, boolean online, HttpServletResponse response) throws IOException; +} diff --git a/src/main/java/com/chinaweal/youfool/devops/base/service/ITaskHandleService.java b/src/main/java/com/chinaweal/youfool/devops/base/service/ITaskHandleService.java new file mode 100644 index 0000000..5b2b3f3 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/base/service/ITaskHandleService.java @@ -0,0 +1,44 @@ +package com.chinaweal.youfool.devops.base.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.chinaweal.youfool.devops.base.entity.TaskHandle; +import com.chinaweal.youfool.framework.springboot.base.query.BaseQuery; + +import java.util.List; + +/** + *

+ * 任务处理流程记录 服务类 + *

+ * + * @author chinaweal + * @since 2022-03-17 + */ +public interface ITaskHandleService extends IService { + + /** + * 通用的节点标识 + */ + String STRART = "start"; //开始 + String END = "end"; //结束 + String ASSIGN = "assign";//分派 + String FEEDBACK = "feedback";//处理反馈 + String UNRESOLVED = "unresolved";//未解决 + String RESOLVED = "resolved";//已解决 + + /** + * 分页查询任务处理流程记录 + */ + IPage listTaskHandle(BaseQuery query); + + /** + * 流程下一步,更新 + */ + void next(TaskHandle taskHandle); + + /** + * 通过任务id获取流程跟踪记录 + */ + List listByTaskId(String taskId); +} diff --git a/src/main/java/com/chinaweal/youfool/devops/base/service/ITaskListService.java b/src/main/java/com/chinaweal/youfool/devops/base/service/ITaskListService.java new file mode 100644 index 0000000..7a7fb77 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/base/service/ITaskListService.java @@ -0,0 +1,33 @@ +package com.chinaweal.youfool.devops.base.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.chinaweal.youfool.devops.base.entity.TaskHandle; +import com.chinaweal.youfool.devops.base.entity.TaskList; +import com.chinaweal.youfool.framework.springboot.base.query.BaseQuery; + +/** + *

+ * 待办表 服务类 + *

+ * + * @author chinaweal + * @since 2022-03-17 + */ +public interface ITaskListService extends IService { + + /** + * 业务类型 + */ + String BUS_TYPE_ASSIGN = "assign";//领导交办 + + /** + * 分页查询待办表 + */ + IPage listTaskList(BaseQuery query); + + /** + * 新建任务 + */ + TaskHandle createTask(TaskList task, String result); +} diff --git a/src/main/java/com/chinaweal/youfool/devops/base/service/impl/DictServiceImpl.java b/src/main/java/com/chinaweal/youfool/devops/base/service/impl/DictServiceImpl.java new file mode 100644 index 0000000..523669f --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/base/service/impl/DictServiceImpl.java @@ -0,0 +1,90 @@ +package com.chinaweal.youfool.devops.base.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.metadata.OrderItem; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.chinaweal.youfool.devops.base.entity.Dict; +import com.chinaweal.youfool.devops.base.mapper.DictMapper; +import com.chinaweal.youfool.devops.base.service.IDictService; +import com.chinaweal.youfool.framework.springboot.base.query.BaseQuery; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + *

+ * 字典 服务实现类 + *

+ * + * @author chinaweal + * @since 2020-07-07 + */ +@Service("devopsDictServiceImpl") +@Transactional("devopsTransactionManager") +public class DictServiceImpl extends ServiceImpl implements IDictService { + + @Override + public List listByType(String type) { + LambdaQueryWrapper qw = new LambdaQueryWrapper<>(); + qw.eq(Dict::getType, type) + .orderByAsc(Dict::getSort); + List list = list(qw); + return list; + } + + @Override + public Dict getByTypeAndCode(String type, String code) { + LambdaQueryWrapper qw = new LambdaQueryWrapper<>(); + qw.eq(Dict::getType, type).eq(Dict::getCode, code); + Dict dict = getOne(qw); + return dict; + } + + @Override + public void saveNameByTypeCode(String type, String code, String name) { + Dict dict = getByTypeAndCode(type, code); + if (dict == null) { + dict = new Dict(); + dict.setType(type); + dict.setCode(code); + dict.setName(name); + save(dict); + } + } + + @Override + public IPage list(BaseQuery query) { + Dict entity = query.getEntity(Dict.class); + Page page = query.getPage(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + + lqw.eq(Dict::getType, entity.getType()); + lqw.like(StringUtils.isNotBlank(entity.getName()), Dict::getName, entity.getName()); + + if (page.getOrders().isEmpty()) { + page.addOrder(OrderItem.desc("update_time")); + } + + return page(page, lqw); + } + + @Override + public void addDict(String type, String name) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(Dict::getType, type).eq(Dict::getName, name); + Dict dict = getOne(lqw); + if (dict == null) { + //不存在,则新增 + dict = new Dict(); + dict.setType(type); + dict.setCode(name); + dict.setName(name); + save(dict); + } + } +} diff --git a/src/main/java/com/chinaweal/youfool/devops/base/service/impl/MonitorServiceImpl.java b/src/main/java/com/chinaweal/youfool/devops/base/service/impl/MonitorServiceImpl.java new file mode 100644 index 0000000..d1d33c4 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/base/service/impl/MonitorServiceImpl.java @@ -0,0 +1,115 @@ +package com.chinaweal.youfool.devops.base.service.impl; + +import com.chinaweal.youfool.devops.base.service.IMonitorService; +import com.chinaweal.youfool.devops.repair.api.RobotApi; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.time.DateFormatUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.sql.Connection; +import java.sql.Driver; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.util.*; + +@Service +@Slf4j +public class MonitorServiceImpl implements IMonitorService { + + @Value("${dbUsernames}") + private String[] dbUsernames; + + @Value("${dbWebhookKeys}") + private String[] dbWebhookKeys; + + @Resource + private RobotApi robotApi; + + @Override + public void countDbPwdExpireAndSendWx() throws Exception { + List list = new ArrayList<>(); + //145数据库 + list = findExpireUserInfo("jdbc:oracle:thin:@19.130.241.145:1521:FSAMRDATA", "system", "Chinaweal", "19.130.241.145"); + //147数据库 + list.addAll(findExpireUserInfo("jdbc:oracle:thin:@19.130.241.147:1521:FSAMRDATA", "system", "Chinaweal_2022", "19.130.241.147")); + //152数据库 + list.addAll(findExpireUserInfo("jdbc:oracle:thin:@19.130.241.152:1521:FSAMRDATA", "system", "Chinaweal", "19.130.241.152")); + //顺德133数据库 + list.addAll(findExpireUserInfo("jdbc:oracle:thin:@19.202.179.133:1521:SDAMRDATA", "system", "ChinaWeal_2020", "19.202.179.133")); + + if (list.size() == 0) { + //没有账号过期,则不需要提醒 + return; + } + + String tip = "数据库账号密码过期提醒,有" + list.size() + "个账号即将过期!\n" + + "主机 -> 账号 -> 过期时间\n"; + for (String s : list) { + //拼接账号 + tip += s; + } + Map content = new HashMap<>(); + content.put("content", tip); + content.put("mentioned_mobile_list", new String[]{"13827173481"}); + + Map query = new HashMap<>(); + query.put("msgtype", "text"); + query.put("text", content); + + for (String dbWebhookKey : dbWebhookKeys) { + robotApi.webhookSend(query, dbWebhookKey); + } + } + + /** + * 获取过期账号列表信息文本 + */ + private List findExpireUserInfo(String jdbc, String user, String pwd, String ip) { + //动态加载,减少依赖性 + List list = new ArrayList<>(); + try { + Class aClass = Class.forName("oracle.jdbc.driver.OracleDriver"); + Driver driver = (Driver) aClass.getDeclaredConstructor().newInstance(); + Properties properties = new Properties(); + properties.setProperty("user", user); + properties.setProperty("password", pwd); + //properties.setProperty("internal_logon", "sysdba"); + Connection connect = driver.connect(jdbc, properties); + String sql = "select username,account_status,EXPIRY_DATE from dba_users " + + "where EXPIRY_DATE - 7 < sysdate and USERNAME in"; + + String join = StringUtils.join(dbUsernames, "','"); + sql = sql + "('" + join + "')"; + PreparedStatement pre = connect.prepareStatement(sql); + ResultSet resultSet = pre.executeQuery(); + list = new ArrayList<>(); + while (resultSet.next()) { + String username = resultSet.getString("USERNAME"); + //String accountStatus = resultSet.getString("ACCOUNT_STATUS"); + Date expiryDate = resultSet.getDate("EXPIRY_DATE"); + String text = ip + " -> " + username + " -> " + (expiryDate != null ? DateFormatUtils.format(expiryDate, "yyyy-MM-dd HH:mm:ss") : "") + "\n"; + list.add(text); + } + } catch (Exception e) { + log.error("连接{}数据库出错!", jdbc, e); + String tip = ip + "数据库,用户:" + user + ",连接出错,请检查!"; + tip += "\n错误信息:" + e; + Map content = new HashMap<>(); + content.put("content", tip); + content.put("mentioned_mobile_list", new String[]{"13827173481"}); + + Map query = new HashMap<>(); + query.put("msgtype", "text"); + query.put("text", content); + + for (String dbWebhookKey : dbWebhookKeys) { + robotApi.webhookSend(query, dbWebhookKey); + } + } + return list; + } + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/base/service/impl/TaskFileServiceImpl.java b/src/main/java/com/chinaweal/youfool/devops/base/service/impl/TaskFileServiceImpl.java new file mode 100644 index 0000000..13ad688 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/base/service/impl/TaskFileServiceImpl.java @@ -0,0 +1,171 @@ +package com.chinaweal.youfool.devops.base.service.impl; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.date.TimeInterval; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.chinaweal.youfool.devops.base.entity.TaskFile; +import com.chinaweal.youfool.devops.base.mapper.TaskFileMapper; +import com.chinaweal.youfool.devops.base.service.ITaskFileService; +import com.chinaweal.youfool.framework.springboot.base.query.BaseQuery; +import com.chinaweal.youfool.framework.springboot.util.DateTimeUtils; +import lombok.extern.slf4j.Slf4j; +import net.coobird.thumbnailator.Thumbnails; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +/** + *

+ * 任务附件 服务实现类 + *

+ * + * @author chinaweal + * @since 2022-03-17 + */ +@Service +@Slf4j +@Transactional("devopsTransactionManager") +public class TaskFileServiceImpl extends ServiceImpl implements ITaskFileService { + + @Value("${file.devopsDir}") + private String devopsDir; + + @Override + public IPage listTaskFile(BaseQuery query) { + TaskFile entity = query.getEntity(TaskFile.class); + Page page = query.getPage(); + + LambdaQueryWrapper lambdaQueryWrapper = Wrappers.lambdaQuery(); + + return page(page, lambdaQueryWrapper); + } + + @Override + public Map updateFile(MultipartFile multipartFile, String taskId, String type, String handleId) throws IOException { + TaskFile taskFile = new TaskFile(); + + taskFile.setTaskId(taskId); + taskFile.setFileName(multipartFile.getOriginalFilename()); + taskFile.setFileType(multipartFile.getContentType()); + taskFile.setType(type); + taskFile.setHandleId(handleId); + taskFile.setUploadTime(LocalDateTime.now()); + int i = multipartFile.getOriginalFilename().lastIndexOf("."); + String filePathName = UUID.randomUUID().toString(); + if (i > 0) { + filePathName += multipartFile.getOriginalFilename().substring(i); + } + filePathName = filePath(taskFile.getType()) + File.separator + filePathName; + taskFile.setFilePath(filePathName); + + File file = new File(devopsDir + File.separator + filePathName); + file.mkdirs(); + try (InputStream is = multipartFile.getInputStream();) { + if (StringUtils.containsIgnoreCase(multipartFile.getContentType(), "image") + && multipartFile.getSize() >= 2 * 1024 * 1024) { // 大于2M进行压缩 + //压缩图片 + TimeInterval timer = DateUtil.timer(); + Thumbnails.of(is).scale(1f).outputQuality(0.5f).toFile(file); + log.debug("图片压缩耗时: {} ms", timer.interval()); + } else { + multipartFile.transferTo(file); + } + } catch (IOException e) { + log.error("上传出错", e); + throw new RuntimeException(e.getMessage()); + } + taskFile.setFileSize(file.length()); + save(taskFile); + + Map body = new LinkedHashMap<>(); + body.put("id", taskFile.getId()); + body.put("taskId", taskFile.getTaskId()); + return body; + } + + @Override + public String filePath(String type) { + return type + File.separator + LocalDate.now().format(DateTimeUtils.SHORT_DATE_FORMATTER); + } + + @Override + public void deleteFile(String id) { + TaskFile taskFile = getById(id); + if (taskFile == null) { + return; + } + File file = new File(devopsDir + taskFile.getFilePath()); + if (file.exists()) { + file.delete(); + } + removeById(id); + } + + @Override + public List listByTaskIdAndType(String taskId, String type) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(TaskFile::getTaskId, taskId) + .eq(TaskFile::getType, type) + .orderByAsc(TaskFile::getUploadTime); + + return list(lqw); + } + + @Override + public List listByHandleId(String handleId) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(TaskFile::getHandleId, handleId) + .orderByAsc(TaskFile::getUploadTime); + + return list(lqw); + } + + @Override + public void downloadFile(String id, boolean online, HttpServletResponse response) throws IOException { + TaskFile taskFile = getById(id); + if (taskFile == null) { + return; + } + //拼接绝对路径,获取流 + InputStream is; + try { + is = new FileInputStream(devopsDir + "/" + taskFile.getFilePath()); + } catch (FileNotFoundException e) { + log.warn(e.getMessage()); + return; + } + OutputStream os = response.getOutputStream(); + String fileName = new String(taskFile.getFileName().getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1); + if (online) { + //直接展示 + response.setHeader("Content-Disposition", "inline; filename=\"" + fileName + "\""); + } else { + //设置:当浏览器收到这份资源的时候,以下载的方式提醒用户,而不是直接显示 + response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\""); + } + byte[] buffer = new byte[4096]; + int len; + while ((len = is.read(buffer)) != -1) { + os.write(buffer, 0, len); + } + os.close(); + is.close(); + } + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/base/service/impl/TaskHandleServiceImpl.java b/src/main/java/com/chinaweal/youfool/devops/base/service/impl/TaskHandleServiceImpl.java new file mode 100644 index 0000000..29a2bd0 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/base/service/impl/TaskHandleServiceImpl.java @@ -0,0 +1,82 @@ +package com.chinaweal.youfool.devops.base.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.chinaweal.youfool.devops.base.entity.TaskHandle; +import com.chinaweal.youfool.devops.base.entity.TaskList; +import com.chinaweal.youfool.devops.base.mapper.TaskHandleMapper; +import com.chinaweal.youfool.devops.base.service.ITaskHandleService; +import com.chinaweal.youfool.devops.base.service.ITaskListService; +import com.chinaweal.youfool.framework.springboot.base.query.BaseQuery; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.List; + +/** + *

+ * 任务处理流程记录 服务实现类 + *

+ * + * @author chinaweal + * @since 2022-03-17 + */ +@Service +@Transactional("devopsTransactionManager") +public class TaskHandleServiceImpl extends ServiceImpl implements ITaskHandleService { + + @Resource + private ITaskListService iTaskListService; + + @Override + public IPage listTaskHandle(BaseQuery query) { + TaskHandle entity = query.getEntity(TaskHandle.class); + Page page = query.getPage(); + + LambdaQueryWrapper lambdaQueryWrapper = Wrappers.lambdaQuery(); + + return page(page, lambdaQueryWrapper); + } + + @Override + public void next(TaskHandle taskHandle) { + //失效之前的有效状态 + LambdaUpdateWrapper ulq = Wrappers.lambdaUpdate(); + ulq.eq(TaskHandle::getTaskId, taskHandle.getTaskId()) + .set(TaskHandle::getStatus, "0"); + update(ulq); + + //获取最后的order_index值 + Long index = baseMapper.maxOrderIndex(taskHandle.getTaskId()); + if (index == null) { + index = 0L; + } + taskHandle.setHappenTime(LocalDateTime.now()); + taskHandle.setStatus("1"); + taskHandle.setOrderIndex((int) (index + 1)); + save(taskHandle); + + //更新taskList的step字段和处理时间字段 + LambdaUpdateWrapper uqw = Wrappers.lambdaUpdate(); + uqw.eq(TaskList::getTaskId, taskHandle.getTaskId()) + .set(TaskList::getStep, taskHandle.getStep()) + .set(TaskList::getHandleTime, LocalDateTime.now()); + iTaskListService.update(uqw); + } + + @Override + public List listByTaskId(String taskId) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(TaskHandle::getTaskId, taskId); + lqw.orderByAsc(TaskHandle::getOrderIndex); + List list = list(lqw); + return list; + } + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/base/service/impl/TaskListServiceImpl.java b/src/main/java/com/chinaweal/youfool/devops/base/service/impl/TaskListServiceImpl.java new file mode 100644 index 0000000..9db3246 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/base/service/impl/TaskListServiceImpl.java @@ -0,0 +1,65 @@ +package com.chinaweal.youfool.devops.base.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.chinaweal.youfool.devops.base.entity.TaskHandle; +import com.chinaweal.youfool.devops.base.entity.TaskList; +import com.chinaweal.youfool.devops.base.mapper.TaskListMapper; +import com.chinaweal.youfool.devops.base.service.ITaskHandleService; +import com.chinaweal.youfool.devops.base.service.ITaskListService; +import com.chinaweal.youfool.framework.springboot.base.query.BaseQuery; +import com.chinaweal.youfool.framework.springboot.util.ConstantsUtil; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; + +/** + *

+ * 待办表 服务实现类 + *

+ * + * @author chinaweal + * @since 2022-03-17 + */ +@Service +@Transactional("devopsTransactionManager") +public class TaskListServiceImpl extends ServiceImpl implements ITaskListService { + + @Resource + private ITaskHandleService iTaskHandleService; + + @Override + public IPage listTaskList(BaseQuery query) { + TaskList entity = query.getEntity(TaskList.class); + Page page = query.getPage(); + + LambdaQueryWrapper lambdaQueryWrapper = Wrappers.lambdaQuery(); + + return page(page, lambdaQueryWrapper); + } + + @Override + public TaskHandle createTask(TaskList task, String result) { + task.setStep(ITaskHandleService.STRART); + task.setDeleted(ConstantsUtil.NOT_DELETED); + save(task); + + //插入流程表,启动流程 + TaskHandle taskHandle = new TaskHandle(); + taskHandle.setTaskId(task.getTaskId()); + taskHandle.setStep(task.getStep()); + taskHandle.setHandleUserId(task.getSendId()); + taskHandle.setHandleNickname(task.getSendName()); + taskHandle.setHandleUsername(task.getSendUsername()); + taskHandle.setBusType(task.getBusType()); + taskHandle.setResult(result); + iTaskHandleService.next(taskHandle); + + return taskHandle; + } + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/config/CorsConfig.java b/src/main/java/com/chinaweal/youfool/devops/config/CorsConfig.java new file mode 100644 index 0000000..656bc8c --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/config/CorsConfig.java @@ -0,0 +1,25 @@ +package com.chinaweal.youfool.devops.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpHeaders; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class CorsConfig { + @Bean + public WebMvcConfigurer corsConfigurer() { + return new WebMvcConfigurer() { + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/statistic/**"). + allowedOrigins("*"). //允许跨域的域名,可以用*表示允许任何域名使用 + allowedMethods("*"). //允许任何方法(post、get等) + allowedHeaders("*"). //允许任何请求头 + allowCredentials(true). //带上cookie信息 + exposedHeaders(HttpHeaders.SET_COOKIE).maxAge(3600L); //maxAge(3600)表明在3600秒内,不需要再发送预检验请求,可以缓存该结果 + } + }; + } +} diff --git a/src/main/java/com/chinaweal/youfool/devops/config/DevopsDataSource.java b/src/main/java/com/chinaweal/youfool/devops/config/DevopsDataSource.java new file mode 100644 index 0000000..ae82336 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/config/DevopsDataSource.java @@ -0,0 +1,70 @@ +package com.chinaweal.youfool.devops.config; + +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; +import com.baomidou.mybatisplus.core.config.GlobalConfig; +import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; +import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean; +import com.chinaweal.youfool.framework.springboot.mybatis.plus.CommonMetaObjectHandler; +import org.apache.ibatis.session.SqlSessionFactory; +import org.mybatis.spring.SqlSessionTemplate; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.jdbc.datasource.DataSourceTransactionManager; + +import javax.sql.DataSource; + +/** + * 运维模块的数据源 + * + * @author itluck + */ + +@Configuration +@MapperScan(basePackages = {"com.chinaweal.youfool.devops.repair.**.mapper", "com.chinaweal.youfool.devops.base.**.mapper", "com.chinaweal.youfool.devops.leaderassign.**.mapper", "com.chinaweal.youfool.devops.org.mapper"}, sqlSessionTemplateRef = "devopsSqlSessionTemplate") +public class DevopsDataSource { + + + @Bean(name = "devopsDS", initMethod = "init", destroyMethod = "close") + @ConfigurationProperties(prefix = "spring.datasource.devops") + @Primary + public DruidDataSource dataSource() { + return DruidDataSourceBuilder.create().build(); + } + + @Bean(name = "devopsSqlSessionFactory") + public MybatisSqlSessionFactoryBean sqlSessionFactory(@Qualifier("devopsDS") DataSource dataSource) throws Exception { + MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean(); + bean.setDataSource(dataSource); + GlobalConfig globalConfig = new GlobalConfig(); + globalConfig.setMetaObjectHandler(new CommonMetaObjectHandler()); + bean.setGlobalConfig(globalConfig); + bean.setConfigLocation(new ClassPathResource("mybatis/mybatis-config.xml")); + bean.setPlugins(paginationInterceptor());// 分页插件 + bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mybatis/mapper/**/*.xml")); + return bean; + } + + @Bean(name = "devopsTransactionManager") + public DataSourceTransactionManager transactionManager(@Qualifier("devopsDS") DataSource dataSource) { + return new DataSourceTransactionManager(dataSource); + } + + @Bean(name = "devopsSqlSessionTemplate") + public SqlSessionTemplate sqlSessionTemplate(@Qualifier("devopsSqlSessionFactory") SqlSessionFactory sqlSessionFactory) { + return new SqlSessionTemplate(sqlSessionFactory); + } + + public PaginationInterceptor paginationInterceptor() { + PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); + // 设置最大单页限制数量,默认 500 条,-1 不受限制 + paginationInterceptor.setLimit(-1); + return paginationInterceptor; + } +} diff --git a/src/main/java/com/chinaweal/youfool/devops/config/FilterConfig.java b/src/main/java/com/chinaweal/youfool/devops/config/FilterConfig.java new file mode 100644 index 0000000..66158a1 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/config/FilterConfig.java @@ -0,0 +1,39 @@ +package com.chinaweal.youfool.devops.config; + +import com.chinaweal.youfool.framework.springboot.filter.RepeatlyReadFilter; +import com.chinaweal.youfool.framework.springboot.log.filter.RestLogFilter; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author itluck + */ +@Configuration +public class FilterConfig { + /** + * 日志记录过滤器 + */ + @Bean + public FilterRegistrationBean restLogFilter() { + FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); + registrationBean.setFilter(new RestLogFilter()); + registrationBean.addUrlPatterns("/*"); + registrationBean.setName("restLogFilter"); + registrationBean.setOrder(-99); + return registrationBean; + } + + /** + * 开启重复读取request流,用于日志 + */ + @Bean + public FilterRegistrationBean repeatlyReadFilter() { + FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); + registrationBean.setFilter(new RepeatlyReadFilter()); + registrationBean.addUrlPatterns("/*"); + registrationBean.setName("repeatlyReadFilter"); + registrationBean.setOrder(-100); + return registrationBean; + } +} diff --git a/src/main/java/com/chinaweal/youfool/devops/config/InterceptorConfig.java b/src/main/java/com/chinaweal/youfool/devops/config/InterceptorConfig.java new file mode 100644 index 0000000..bb5bba3 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/config/InterceptorConfig.java @@ -0,0 +1,50 @@ +package com.chinaweal.youfool.devops.config; + +import com.chinaweal.youfool.devops.org.interceptor.LoginInterceptor; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.List; + +@Configuration +public class InterceptorConfig implements WebMvcConfigurer { + @Resource + private LoginInterceptor loginInterceptor; + + @Override + public void addInterceptors(InterceptorRegistry registry) { + InterceptorRegistration registration = registry.addInterceptor(loginInterceptor); + registration.addPathPatterns("/**"); + + //添加不拦截路径 + List excludes = new ArrayList<>(); + excludes.add("/**/*.html"); + excludes.add("/**/*.js"); + excludes.add("/**/*.css"); + excludes.add("/**/*.woff"); + excludes.add("/**/*.ttf"); + excludes.add("/**/*.png"); +// excludes.add("/swagger-resources/**"); + excludes.add("/user/loginBusiness"); + excludes.add("/user/loginOuter"); + excludes.add("/user/loginEngineer"); + excludes.add("/user/vcode"); + excludes.add("/user/clearFreq"); + excludes.add("/repair/downloadFile"); + excludes.add("/repair/uploadFile"); + excludes.add("/repair/notification/**"); + excludes.add("/repair/exportTodo"); + excludes.add("/statistic/exportSumSummary"); + excludes.add("/statistic/exportListByItemId"); + excludes.add("/statistic/exportGroupOrg"); + excludes.add("/statistic/countRepairStepByUserId"); + excludes.add("/base/taskFile/uploadFile"); + excludes.add("/base/taskFile/downloadFile"); + + registration.excludePathPatterns(excludes); + } +} diff --git a/src/main/java/com/chinaweal/youfool/devops/config/PropertySourceConfig.java b/src/main/java/com/chinaweal/youfool/devops/config/PropertySourceConfig.java new file mode 100644 index 0000000..81dcae7 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/config/PropertySourceConfig.java @@ -0,0 +1,20 @@ +package com.chinaweal.youfool.devops.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; +import org.springframework.stereotype.Component; + +/** + * 引入properties常用值 + */ +@Component +@Configuration +@PropertySource(value = {"classpath:properties/youfool-devops.properties"}, encoding = "UTF-8") +public class PropertySourceConfig { + @Bean + public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { + return new PropertySourcesPlaceholderConfigurer(); + } +} \ No newline at end of file diff --git a/src/main/java/com/chinaweal/youfool/devops/config/SchedulingXmlConfig.java b/src/main/java/com/chinaweal/youfool/devops/config/SchedulingXmlConfig.java new file mode 100644 index 0000000..8c4a173 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/config/SchedulingXmlConfig.java @@ -0,0 +1,14 @@ +package com.chinaweal.youfool.devops.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.ImportResource; + +/** + * 引用定时任务的xml + */ + +@Configuration +@ImportResource(locations = {"classpath:spring-timer.xml"}) +public class SchedulingXmlConfig { + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/config/SwaggerKnife4j.java b/src/main/java/com/chinaweal/youfool/devops/config/SwaggerKnife4j.java new file mode 100644 index 0000000..ccb6a35 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/config/SwaggerKnife4j.java @@ -0,0 +1,123 @@ +package com.chinaweal.youfool.devops.config; + +import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.ParameterBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.schema.ModelRef; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.service.Contact; +import springfox.documentation.service.Parameter; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author itluck + */ +@Configuration +@EnableSwagger2 +@EnableKnife4j +@ConditionalOnProperty(value = "swagger.enable", havingValue = "true") +public class SwaggerKnife4j { + @Value("${applicationName}") + private String applicationName; + @Value("${version}") + private String version; + @Value("${description}") + private String description; + @Value("${license}") + private String license; + + @Bean("orgApi") + public Docket orgApi() { + ParameterBuilder tokenPar = new ParameterBuilder(); + List headers = new ArrayList<>(); + tokenPar.name("token").description("令牌").modelRef(new ModelRef("string")).parameterType("header").required(false).build(); + headers.add(tokenPar.build()); + return new Docket(DocumentationType.SWAGGER_2) + .enable(true) + .apiInfo(apiInfo()) + .groupName("组织架构") + .select() + .apis(RequestHandlerSelectors.basePackage("com.chinaweal.youfool.devops.org")) + .paths(PathSelectors.any()) + .build() + .globalOperationParameters(headers); + } + + @Bean("devopsApi") + public Docket devopsApi() { + //添加head参数start + ParameterBuilder tokenPar = new ParameterBuilder(); + List headers = new ArrayList<>(); + tokenPar.name("token").description("令牌").modelRef(new ModelRef("string")).parameterType("header").required(false).build(); + headers.add(tokenPar.build()); + return new Docket(DocumentationType.SWAGGER_2) + .enable(true) + .apiInfo(apiInfo()) + .groupName("运维报障") + .select() + .apis(RequestHandlerSelectors.basePackage("com.chinaweal.youfool.devops.repair")) + .paths(PathSelectors.any()) + .build() + .globalOperationParameters(headers); + } + + @Bean("basisApi") + public Docket basisApi() { + //添加head参数start + ParameterBuilder tokenPar = new ParameterBuilder(); + List headers = new ArrayList<>(); + tokenPar.name("token").description("令牌").modelRef(new ModelRef("string")).parameterType("header").required(false).build(); + headers.add(tokenPar.build()); + return new Docket(DocumentationType.SWAGGER_2) + .enable(true) + .apiInfo(apiInfo()) + .groupName("基础环境") + .select() + .apis(RequestHandlerSelectors.basePackage("com.chinaweal.youfool.devops.base")) + .paths(PathSelectors.any()) + .build() + .globalOperationParameters(headers); + } + + @Bean("websocketApi") + public Docket websocketApi() { + //添加head参数start + ParameterBuilder tokenPar = new ParameterBuilder(); + List headers = new ArrayList<>(); + tokenPar.name("token").description("令牌").modelRef(new ModelRef("string")).parameterType("header").required(false).build(); + headers.add(tokenPar.build()); + return new Docket(DocumentationType.SWAGGER_2) + .enable(true) + .apiInfo(apiInfo()) + .groupName("WebSocket测试环境") + .select() + .apis(RequestHandlerSelectors.basePackage("com.chinaweal.youfool.devops.websocket")) + .paths(PathSelectors.any()) + .build() + .globalOperationParameters(headers); + } + + + private ApiInfo apiInfo() { + return new ApiInfoBuilder() + .title(applicationName) + .description(description) + .termsOfServiceUrl("https://www.chinaweal.com.cn") + .version(version) + .contact(new Contact("chinaweal", "https://www.chinaweal.com.cn", "")) + .license(license) + .licenseUrl("https://www.chinaweal.com.cn") + .build(); + } +} diff --git a/src/main/java/com/chinaweal/youfool/devops/config/YoufoolDataSource.java b/src/main/java/com/chinaweal/youfool/devops/config/YoufoolDataSource.java new file mode 100644 index 0000000..3b7dc5c --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/config/YoufoolDataSource.java @@ -0,0 +1,59 @@ +package com.chinaweal.youfool.devops.config; + +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; +import com.baomidou.mybatisplus.core.config.GlobalConfig; +import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean; +import com.chinaweal.youfool.framework.springboot.mybatis.plus.CommonMetaObjectHandler; +import org.apache.ibatis.session.SqlSessionFactory; +import org.mybatis.spring.SqlSessionTemplate; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.jdbc.datasource.DataSourceTransactionManager; + +import javax.sql.DataSource; + +/** + * youfool基础的数据源 + * + * @author itluck + */ + +@Configuration +@MapperScan(basePackages = "com.chinaweal.youfool.framework.springboot.**.mapper", sqlSessionTemplateRef = "youfoolSqlSessionTemplate") +public class YoufoolDataSource { + + + @Bean(name = "youfoolDS", initMethod = "init", destroyMethod = "close") + @ConfigurationProperties(prefix = "spring.datasource.youfool") + public DruidDataSource dataSource() { + return DruidDataSourceBuilder.create().build(); + } + + @Bean(name = "youfoolSqlSessionFactory") + public MybatisSqlSessionFactoryBean sqlSessionFactory(@Qualifier("youfoolDS") DataSource dataSource) throws Exception { + MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean(); + bean.setDataSource(dataSource); + GlobalConfig globalConfig = new GlobalConfig(); + globalConfig.setMetaObjectHandler(new CommonMetaObjectHandler()); + bean.setGlobalConfig(globalConfig); + bean.setConfigLocation(new ClassPathResource("youfool/mybatis/mybatis-config.xml")); + bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:youfool/mybatis/mapper/**/*.xml")); + return bean; + } + + @Bean(name = "youfoolTransactionManager") + public DataSourceTransactionManager transactionManager(@Qualifier("youfoolDS") DataSource dataSource) { + return new DataSourceTransactionManager(dataSource); + } + + @Bean(name = "youfoolSqlSessionTemplate") + public SqlSessionTemplate sqlSessionTemplate(@Qualifier("youfoolSqlSessionFactory") SqlSessionFactory sqlSessionFactory) { + return new SqlSessionTemplate(sqlSessionFactory); + } +} diff --git a/src/main/java/com/chinaweal/youfool/devops/dev/MybatisPlusCodeGenerator.java b/src/main/java/com/chinaweal/youfool/devops/dev/MybatisPlusCodeGenerator.java new file mode 100644 index 0000000..c80f047 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/dev/MybatisPlusCodeGenerator.java @@ -0,0 +1,14 @@ +package com.chinaweal.youfool.devops.dev; + + +import com.chinaweal.youfool.framework.springboot.mybatis.plus.CodeGenerator; + +/** + * 代码生成器 + */ +public class MybatisPlusCodeGenerator { + public static void main(String[] args) { + CodeGenerator codeGenerator = new CodeGenerator("properties/codeCenerator"); + codeGenerator.generateCode(); + } +} diff --git a/src/main/java/com/chinaweal/youfool/devops/leaderassign/controller/AssignController.java b/src/main/java/com/chinaweal/youfool/devops/leaderassign/controller/AssignController.java new file mode 100644 index 0000000..3cc841c --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/leaderassign/controller/AssignController.java @@ -0,0 +1,89 @@ +package com.chinaweal.youfool.devops.leaderassign.controller; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.chinaweal.youfool.devops.leaderassign.controller.dto.AssignHandleQuery; +import com.chinaweal.youfool.devops.leaderassign.controller.dto.TaskAssignVo; +import com.chinaweal.youfool.devops.leaderassign.entity.Assign; +import com.chinaweal.youfool.devops.leaderassign.service.IAssignService; +import com.chinaweal.youfool.framework.springboot.rest.RestResult; +import com.chinaweal.youfool.framework.springboot.util.AssertUtils; +import com.github.xiaoymin.knife4j.annotations.ApiSort; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.Map; + +/** + *

+ * 领导交办详情 控制器 + *

+ * + * @author chinaweal + * @since 2022-03-17 + */ +@Api(tags = "领导交办详情") +@ApiSort(1) +@RestController +@RequestMapping("/assign") +public class AssignController { + + @Resource + private IAssignService iAssignService; + + @ApiOperation(value = "1.新增领导交办详情", position = 1) + @PostMapping("/save") + public RestResult saveAssign(@RequestBody @Valid Assign assign, BindingResult bindingResult) { + AssertUtils.isBndingValidit(bindingResult); + assign = iAssignService.saveAssign(assign); + return RestResult.ok(assign); + } + + @ApiOperation(value = "2.分页查询领导交办列表", position = 2) + @PostMapping("/listTask") + public RestResult> listTask(@RequestBody Map map) { + IPage data = iAssignService.listTask(map); + return RestResult.ok(data); + } + + @ApiOperation(value = "3.查看领导交办详情", position = 3) + @GetMapping("/getAssign") + public RestResult getAssign(@RequestParam @ApiParam("bizId") String bizId) { + Assign assign = iAssignService.getAssign(bizId); + return RestResult.ok(assign); + } + + @ApiOperation(value = "4.删除领导交办", position = 4) + @PostMapping("/deleteAssign") + public RestResult deleteAssign(@RequestParam @ApiParam("bizId") String bizId) { + iAssignService.deleteAssign(bizId); + return RestResult.ok(); + } + + @ApiOperation(value = "5.流程节点扭转", position = 5) + @PostMapping("/next") + public RestResult next(@RequestBody AssignHandleQuery data) { + iAssignService.next(data); + return RestResult.ok(); + } + + @ApiOperation(value = "6.更新处理信息", position = 6) + @PostMapping("/updateHandle") + public RestResult updateHandle(@RequestBody Assign assign) { + iAssignService.updateHandle(assign); + return RestResult.ok(); + } + + @ApiOperation(value = "7.更新表单信息", position = 7) + @PostMapping("/updateAssign") + public RestResult updateAssign(@RequestBody Assign assign) { + iAssignService.updateAssign(assign); + return RestResult.ok(); + } + + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/leaderassign/controller/dto/AssignHandleQuery.java b/src/main/java/com/chinaweal/youfool/devops/leaderassign/controller/dto/AssignHandleQuery.java new file mode 100644 index 0000000..f2700cd --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/leaderassign/controller/dto/AssignHandleQuery.java @@ -0,0 +1,48 @@ +package com.chinaweal.youfool.devops.leaderassign.controller.dto; + +import com.chinaweal.youfool.devops.base.entity.TaskHandle; +import com.chinaweal.youfool.framework.springboot.json.LocalDateTimeStringSerializer; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; + +/** + * 领导交办流程操作实体 + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class AssignHandleQuery extends TaskHandle { + + private static final long serialVersionUID = 1L; + + /** + * 交办单号ID + */ + @ApiModelProperty(value = "交办单号ID") + private String bizId; + + /** + * 优先级别;1:紧急;2:高;3:中;4:低 + */ + @ApiModelProperty(value = "优先级别;1:紧急;2:高;3:中;4:低") + private Integer priority; + + /** + * 计划完成时间 + */ + @ApiModelProperty(value = "计划完成时间") + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime plannedTime; + + /** + * 实际完成时间 + */ + @ApiModelProperty(value = "实际完成时间") + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime realityTime; + + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/leaderassign/controller/dto/TaskAssignVo.java b/src/main/java/com/chinaweal/youfool/devops/leaderassign/controller/dto/TaskAssignVo.java new file mode 100644 index 0000000..e386a45 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/leaderassign/controller/dto/TaskAssignVo.java @@ -0,0 +1,172 @@ +package com.chinaweal.youfool.devops.leaderassign.controller.dto; + +import com.chinaweal.youfool.framework.springboot.json.LocalDateTimeStringSerializer; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 领导交办待办列表的vo + */ +@Data +public class TaskAssignVo implements Serializable { + + + /** + * 待办ID + */ + @ApiModelProperty(value = "待办ID") + private String id; + + /** + * 业务表ID,对应业务的表的ID + */ + @ApiModelProperty(value = "业务表ID,对应业务的表的ID") + private String bizId; + + /** + * 标题 + */ + @ApiModelProperty(value = "标题") + private String title; + + /** + * 申报账号ID + */ + @ApiModelProperty(value = "申报账号ID") + private String sendId; + + /** + * 申报用户昵称 + */ + @ApiModelProperty(value = "申报用户昵称") + private String sendName; + + /** + * 申报用户账号 + */ + @ApiModelProperty(value = "申报用户账号") + private String sendUsername; + + /** + * 签收人ID,个人或机构 + */ + @ApiModelProperty(value = "签收人ID,个人或机构") + private String signId; + + /** + * 签收人名称 + */ + @ApiModelProperty(value = "签收人名称") + private String signName; + + /** + * 所属机构Id + */ + @ApiModelProperty(value = "所属机构Id") + private String orgId; + + /** + * 所属机构 + */ + @ApiModelProperty(value = "所属机构") + private String org; + + /** + * 所属部门Id + */ + @ApiModelProperty(value = "所属部门Id") + private String deptId; + + /** + * 所属部门 + */ + @ApiModelProperty(value = "所属部门") + private String dept; + + /** + * 业务类型;assign:领导交办 + */ + @ApiModelProperty(value = "业务类型;assign:领导交办") + private String busType; + + /** + * 优先级别;1:紧急;2:高;3:中;4:低 + */ + @ApiModelProperty(value = "优先级别;1:紧急;2:高;3:中;4:低") + private Integer priority; + + /** + * 紧急程度;1:紧急;2:高;3:中;4:低 + */ + @ApiModelProperty(value = "紧急程度;1:紧急;2:高;3:中;4:低") + private Integer urgency; + + /** + * 环节步骤; + */ + @ApiModelProperty(value = "环节步骤;") + private String step; + + /** + * 催单次数 + */ + @ApiModelProperty(value = "催单次数") + private Integer reminder; + + /** + * 是否删除;0:有效;1:删除 + */ + @ApiModelProperty(value = "是否删除;0:有效;1:删除") + private String deleted; + + /** + * 报送时间 + */ + @ApiModelProperty(value = "报送时间") + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime launchTime; + + /** + * 到期时间 + */ + @ApiModelProperty(value = "到期时间") + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime solveLimitTime; + + /** + * 处理更新时间 + */ + @ApiModelProperty(value = "处理更新时间") + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime handleTime; + + /** + * 任务状态 0:在办;1:办结; + */ + @ApiModelProperty(value = "任务状态 0:在办;1:办结;") + private String status; + + /** + * 事件描述 + */ + @ApiModelProperty(value = "事件描述") + private String content; + + /** + * 交办时间 + */ + @ApiModelProperty(value = "交办时间") + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime assignTime; + + /** + * 计划完成时间 + */ + @ApiModelProperty(value = "计划完成时间") + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime plannedTime; +} diff --git a/src/main/java/com/chinaweal/youfool/devops/leaderassign/entity/Assign.java b/src/main/java/com/chinaweal/youfool/devops/leaderassign/entity/Assign.java new file mode 100644 index 0000000..fb23045 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/leaderassign/entity/Assign.java @@ -0,0 +1,245 @@ +package com.chinaweal.youfool.devops.leaderassign.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import com.chinaweal.youfool.devops.base.entity.TaskFile; +import com.chinaweal.youfool.devops.base.entity.TaskHandle; +import com.chinaweal.youfool.devops.base.entity.TaskList; +import com.chinaweal.youfool.framework.springboot.json.LocalDateTimeStringSerializer; +import com.chinaweal.youfool.framework.springboot.mybatis.plus.SuperEntity; +import com.chinaweal.youfool.framework.springboot.util.ConstantsUtil; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import javax.validation.constraints.NotBlank; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +/** + *

+ * 领导交办详情 + *

+ * + * @author chinaweal + * @since 2022-03-17 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +@TableName("ASSIGN") +@ApiModel(value = "Assign对象", description = "领导交办详情") +public class Assign extends SuperEntity { + + private static final long serialVersionUID = 1L; + + /** + * 交办单号ID + */ + @ApiModelProperty(value = "交办单号ID") + @TableId(value = "BIZ_ID") + private String bizId; + + /** + * 待办id + */ + @ApiModelProperty(value = "待办id") + @TableField("TASK_ID") + private String taskId; + + /** + * 标题 + */ + @ApiModelProperty(value = "标题") + @TableField("TITLE") + @NotBlank(message = "标题不能为空") + private String title; + + /** + * 领导名称 + */ + @ApiModelProperty(value = "领导名称") + @TableField("leader_name") + @NotBlank(message = "领导名称不能为空") + private String leaderName; + + /** + * 申报账号ID + */ + @ApiModelProperty(value = "申报账号ID") + @TableField("SEND_ID") + private String sendId; + + /** + * 申报用户昵称 + */ + @ApiModelProperty(value = "申报用户昵称") + @TableField("SEND_NAME") + private String sendName; + + /** + * 申报用户账号 + */ + @ApiModelProperty(value = "申报用户账号") + @TableField("SEND_USERNAME") + @NotBlank(message = "申报用户账号不能为空") + private String sendUsername; + + + /** + * 处理人id + */ + @ApiModelProperty(value = "处理人id") + @TableField("HANDLE_USERID") + private String handleUserid; + + /** + * 处理人账号 + */ + @ApiModelProperty(value = "处理人账号") + @TableField("HANDLE_USER") + private String handleUser; + + /** + * 处理人 + */ + @ApiModelProperty(value = "处理人") + @TableField("HANDLE_NAME") + private String handleName; + + /** + * 所属机构Id + */ + @ApiModelProperty(value = "所属机构Id") + @TableField("ORG_ID") + private String orgId; + + /** + * 所属机构 + */ + @ApiModelProperty(value = "所属机构") + @TableField("ORG") + private String org; + + /** + * 所属部门Id + */ + @ApiModelProperty(value = "所属部门Id") + @TableField("DEPT_ID") + private String deptId; + + /** + * 所属部门 + */ + @ApiModelProperty(value = "所属部门") + @TableField("DEPT") + private String dept; + + /** + * 联系电话 + */ + @ApiModelProperty(value = "联系电话") + @TableField("PHONE") + private String phone; + + /** + * 事件类型 + */ + @ApiModelProperty(value = "事件类型") + @TableField("EVENT_TYPE") + @NotBlank(message = "事件类型不能为空") + private String eventType; + + /** + * 事件描述 + */ + @ApiModelProperty(value = "事件描述") + @TableField("CONTENT") + private String content; + + /** + * 紧急程度;1:紧急;2:高;3:中;4:低 + */ + @ApiModelProperty(value = "紧急程度;1:紧急;2:高;3:中;4:低") + @TableField("URGENCY") + private Integer urgency; + + /** + * 优先级别;1:紧急;2:高;3:中;4:低 + */ + @ApiModelProperty(value = "优先级别;1:紧急;2:高;3:中;4:低") + @TableField("PRIORITY") + private Integer priority; + + /** + * 交办时间 + */ + @ApiModelProperty(value = "交办时间") + @TableField("ASSIGN_TIME") + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime assignTime; + + /** + * 报送时间 + */ + @ApiModelProperty(value = "报送时间") + @TableField("LAUNCH_TIME") + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime launchTime; + + /** + * 解决期限时间 + */ + @ApiModelProperty(value = "解决期限时间") + @TableField("SOLVE_LIMIT_TIME") + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime solveLimitTime; + + /** + * 计划完成时间 + */ + @ApiModelProperty(value = "计划完成时间") + @TableField("PLANNED_TIME") + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime plannedTime; + + /** + * 实际完成时间 + */ + @ApiModelProperty(value = "实际完成时间") + @TableField("REALITY_TIME") + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime realityTime; + + /** + * 是否删除;0:有效;1:删除 + */ + @ApiModelProperty(value = "是否删除;0:有效;1:删除") + @TableField("DELETED") + @TableLogic(value = ConstantsUtil.NOT_DELETED, delval = ConstantsUtil.DELETED) + private String deleted; + + @TableField(exist = false) + private TaskList taskList; + + @TableField(exist = false) + private List taskHandles = new ArrayList<>(); + + /** + * 提交的附件 + */ + @TableField(exist = false) + private List sourceFiles = new ArrayList<>(); + + /** + * 下一个节点表单 + */ + @TableField(exist = false) + private String nextStep; +} diff --git a/src/main/java/com/chinaweal/youfool/devops/leaderassign/mapper/AssignMapper.java b/src/main/java/com/chinaweal/youfool/devops/leaderassign/mapper/AssignMapper.java new file mode 100644 index 0000000..5cc6c4b --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/leaderassign/mapper/AssignMapper.java @@ -0,0 +1,23 @@ +package com.chinaweal.youfool.devops.leaderassign.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.chinaweal.youfool.devops.leaderassign.controller.dto.TaskAssignVo; +import com.chinaweal.youfool.devops.leaderassign.entity.Assign; +import org.apache.ibatis.annotations.Param; + +import java.util.Map; + +/** + *

+ * 领导交办详情 Mapper 接口 + *

+ * + * @author chinaweal + * @since 2022-03-17 + */ +public interface AssignMapper extends BaseMapper { + + IPage listTask(Page page, @Param("map") Map map); +} diff --git a/src/main/java/com/chinaweal/youfool/devops/leaderassign/service/IAssignService.java b/src/main/java/com/chinaweal/youfool/devops/leaderassign/service/IAssignService.java new file mode 100644 index 0000000..63b6a01 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/leaderassign/service/IAssignService.java @@ -0,0 +1,52 @@ +package com.chinaweal.youfool.devops.leaderassign.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.chinaweal.youfool.devops.leaderassign.controller.dto.AssignHandleQuery; +import com.chinaweal.youfool.devops.leaderassign.controller.dto.TaskAssignVo; +import com.chinaweal.youfool.devops.leaderassign.entity.Assign; + +import java.util.Map; + +/** + *

+ * 领导交办详情 服务类 + *

+ * + * @author chinaweal + * @since 2022-03-17 + */ +public interface IAssignService extends IService { + + + /** + * 新增领导交办详情 + */ + Assign saveAssign(Assign assign); + + /** + * 修改领导交办详情 + */ + void updateAssign(Assign assign); + + /** + * 获取领导交办待办 + */ + IPage listTask(Map map); + + Assign getAssign(String bizId); + + void deleteAssign(String bizId); + + /** + * 流程下一步 + * + * @param data + */ + void next(AssignHandleQuery data); + + /** + * 更新部分处理的信息,例如优先级 + */ + void updateHandle(Assign assign); +} diff --git a/src/main/java/com/chinaweal/youfool/devops/leaderassign/service/impl/AssignServiceImpl.java b/src/main/java/com/chinaweal/youfool/devops/leaderassign/service/impl/AssignServiceImpl.java new file mode 100644 index 0000000..53a622b --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/leaderassign/service/impl/AssignServiceImpl.java @@ -0,0 +1,295 @@ +package com.chinaweal.youfool.devops.leaderassign.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.chinaweal.youfool.devops.base.entity.TaskFile; +import com.chinaweal.youfool.devops.base.entity.TaskHandle; +import com.chinaweal.youfool.devops.base.entity.TaskList; +import com.chinaweal.youfool.devops.base.service.IDictService; +import com.chinaweal.youfool.devops.base.service.ITaskFileService; +import com.chinaweal.youfool.devops.base.service.ITaskHandleService; +import com.chinaweal.youfool.devops.base.service.ITaskListService; +import com.chinaweal.youfool.devops.leaderassign.controller.dto.AssignHandleQuery; +import com.chinaweal.youfool.devops.leaderassign.controller.dto.TaskAssignVo; +import com.chinaweal.youfool.devops.leaderassign.entity.Assign; +import com.chinaweal.youfool.devops.leaderassign.mapper.AssignMapper; +import com.chinaweal.youfool.devops.leaderassign.service.IAssignService; +import com.chinaweal.youfool.devops.org.business.entity.BusinessUser; +import com.chinaweal.youfool.devops.org.business.service.BusinessUserService; +import com.chinaweal.youfool.devops.org.entity.Engineer; +import com.chinaweal.youfool.devops.org.service.IEngineerService; +import com.chinaweal.youfool.framework.springboot.exception.custom.BusinessException; +import com.chinaweal.youfool.framework.springboot.rest.ResultCode; +import com.chinaweal.youfool.framework.springboot.util.ConstantsUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +/** + *

+ * 领导交办详情 服务实现类 + *

+ * + * @author chinaweal + * @since 2022-03-17 + */ +@Slf4j +@Service +@Transactional("devopsTransactionManager") +public class AssignServiceImpl extends ServiceImpl implements IAssignService { + + @Resource + private ITaskFileService iTaskFileService; + @Resource + private ITaskListService iTaskListService; + @Resource + private ITaskHandleService iTaskHandleService; + @Resource + private IDictService iDictService; + @Resource + private IEngineerService iEngineerService; + + @Resource + private BusinessUserService businessUserService; + + @Override + public Assign saveAssign(Assign assign) { + //获取当前的临时id + String tempTaskId = assign.getTaskId(); + //生成待办id + String taskId = UUID.randomUUID().toString().replace("-", ""); + + //如果是工程师人员添加的,则需要获取申报人的账号信息 + if (StringUtils.isBlank(assign.getSendId())) { + BusinessUser user = businessUserService.getByUsername(assign.getSendUsername()); + if (user == null) { + throw new BusinessException(ResultCode.USCID_INVALID.setMessage("找不到申报账号信息")); + } + assign.setSendId(user.getUserId()); + assign.setSendName(user.getNickname()); + assign.setSendUsername(user.getUsername()); + assign.setOrg(user.getOrgName()); + assign.setOrgId(user.getOrgId()); + assign.setDept(user.getUnitName()); + assign.setDeptId(user.getUnitId()); + } + + //保存表单 + assign.setTaskId(taskId); //设置单号 + assign.setBizId(generateAssignId()); //设置单号 + assign.setLaunchTime(LocalDateTime.now()); + assign.setDeleted(ConstantsUtil.NOT_DELETED); + save(assign); + + //生成待办 + TaskList task = new TaskList(); + task.setTaskId(assign.getTaskId()); + task.setBizId(assign.getBizId()); + task.setBusType(ITaskListService.BUS_TYPE_ASSIGN); + task.setLaunchTime(assign.getLaunchTime()); + task.setSendId(assign.getSendId()); + task.setSendName(assign.getSendName()); + task.setSendUsername(assign.getSendUsername()); + task.setPriority(assign.getPriority()); + task.setSolveLimitTime(assign.getSolveLimitTime()); + task.setTitle(assign.getTitle()); + task.setUrgency(assign.getUrgency()); + task.setOrg(assign.getOrg()); + task.setOrgId(assign.getOrgId()); + task.setStatus("0"); + TaskHandle taskHandle = iTaskListService.createTask(task, null); + + //更新附件的临时值 + LambdaUpdateWrapper uwq = Wrappers.lambdaUpdate(); + uwq.eq(TaskFile::getTaskId, tempTaskId) + .set(TaskFile::getTaskId, assign.getTaskId()) + .set(TaskFile::getHandleId, taskHandle.getHandleId()); + iTaskFileService.update(uwq); + + //更新事件类型字典数据 + iDictService.addDict(IDictService.ASSIGN_EVENT_TYPE, assign.getEventType()); + + return assign; + } + + @Override + public void updateAssign(Assign assign) { + updateById(assign); + } + + @Override + public IPage listTask(Map map) { + + Integer current = (Integer) map.getOrDefault("current", 1); + Integer size = (Integer) map.getOrDefault("size", 10); + Page page = new Page<>(current, size); + + return baseMapper.listTask(page, map); + } + + @Override + public Assign getAssign(String bizId) { + //查询交办表单信息 + Assign assign = getById(bizId); + if (assign == null) { + throw new BusinessException(ResultCode.PARAM_IS_INVALID.setMessage("找不到交办表单信息")); + } + //任务待办信息 + TaskList taskList = iTaskListService.getById(assign.getTaskId()); + assign.setTaskList(taskList); + + //提交的附件assignSource + List sourceFiles = iTaskFileService.listByTaskIdAndType(taskList.getTaskId(), "assignSource"); + assign.setSourceFiles(sourceFiles); + + //处理记录集合 + List handleList = iTaskHandleService.listByTaskId(taskList.getTaskId()); + assign.setTaskHandles(handleList); + //获取处理过程中产生的附件 + for (TaskHandle taskHandle : handleList) { + taskHandle.setFiles(iTaskFileService.listByHandleId(taskHandle.getHandleId())); + } + + return assign; + } + + @Override + public void deleteAssign(String bizId) { + Assign assign = getById(bizId); + //逻辑删除表单 + removeById(assign.getBizId()); + //逻辑删除待办表 + iTaskListService.removeById(assign.getTaskId()); + } + + @Override + public void next(AssignHandleQuery data) { + switch (data.getNextStep()) { + case ITaskHandleService.ASSIGN: { + //分派 + assign(data); + break; + } + case ITaskHandleService.FEEDBACK: { + //处理反馈 + feedback(data); + break; + } + case ITaskHandleService.RESOLVED: { + //已解决 + break; + } + case ITaskHandleService.UNRESOLVED: { + //未解决 + break; + } + default: + throw new BusinessException(ResultCode.BUSINESS_LOGIC_ERROR.setMessage("找不到有效的环节节点")); + } + + Assign assign = getById(data.getBizId()); + + //写入当前操作流程记录 + TaskHandle taskHandle = new TaskHandle(); + taskHandle.setHandleId(data.getHandleId()); + taskHandle.setStep(data.getNextStep()); + taskHandle.setResult(data.getResult()); + taskHandle.setTaskId(assign.getTaskId()); + taskHandle.setBusType(ITaskListService.BUS_TYPE_ASSIGN); + + //工程师处理的 + if (ITaskHandleService.RESOLVED.equals(data.getNextStep()) || ITaskHandleService.UNRESOLVED.equals(data.getNextStep())) { + BusinessUser businessUser = businessUserService.getById(data.getHandleUserId()); + taskHandle.setHandleUserId(businessUser.getUserId()); + taskHandle.setHandleUsername(businessUser.getUsername()); + taskHandle.setHandleNickname(businessUser.getNickname()); + } else { + Engineer engineer = iEngineerService.getById(data.getHandleUserId()); + taskHandle.setHandleUserId(engineer.getUserId()); + taskHandle.setHandleUsername(engineer.getUsername()); + taskHandle.setHandleNickname(engineer.getNickname()); + } + + iTaskHandleService.next(taskHandle); + + } + + /** + * 处理反馈 + */ + private void feedback(AssignHandleQuery data) { + Assign assign = getById(data.getBizId()); + Engineer engineer = iEngineerService.getById(data.getHandleUserId()); + //更新表单 + assign.setRealityTime(LocalDateTime.now()); + assign.setHandleName(engineer.getNickname()); + assign.setHandleUser(engineer.getUsername()); + assign.setHandleUserid(engineer.getUserId()); + updateById(assign); + } + + @Override + public void updateHandle(Assign assign) { + Assign dbAssign = getById(assign.getBizId()); + dbAssign.setPriority(assign.getPriority()); + dbAssign.setPlannedTime(assign.getPlannedTime()); + dbAssign.setRealityTime(assign.getRealityTime()); + updateById(dbAssign); + } + + private void assign(AssignHandleQuery data) { + Assign assign = getById(data.getBizId()); + Engineer engineer = iEngineerService.getById(data.getNextHandleUserId()); + //更新待办表的签收人 + TaskList taskList = iTaskListService.getById(assign.getTaskId()); + taskList.setSignId(engineer.getUserId()); + taskList.setSignUsername(engineer.getUsername()); + taskList.setSignName(engineer.getNickname()); + taskList.setPriority(data.getPriority()); + iTaskListService.updateById(taskList); + + assign.setPriority(data.getPriority()); + assign.setPlannedTime(data.getPlannedTime()); + + updateById(assign); + } + + private synchronized String generateAssignId() { + String prefix = "JB" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); + //查询当天有多少条工单 + LambdaQueryWrapper qw = new LambdaQueryWrapper<>(); + qw.ge(Assign::getLaunchTime, LocalDate.now().atStartOfDay()) + .lt(Assign::getLaunchTime, LocalDate.now().atStartOfDay().plusDays(1)); + int count = count(qw) + 1; + //补齐零 + String no = String.format("%04d", count); + String bizId = prefix + no; + Assign assign = getById(bizId); + //效验运维单号的序号唯一不 + int max = 10; + while (assign != null && max != 0) { + log.warn("效验领导交办的序号有重复的,请注意检查数据!重复单号:{}", bizId); + count++; + max--; + no = String.format("%04d", count); + bizId = prefix + no; + assign = getById(bizId); + } + + return bizId; + } + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/org/business/entity/BusinessUser.java b/src/main/java/com/chinaweal/youfool/devops/org/business/entity/BusinessUser.java new file mode 100644 index 0000000..d7ddd70 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/org/business/entity/BusinessUser.java @@ -0,0 +1,49 @@ +package com.chinaweal.youfool.devops.org.business.entity; + +import com.chinaweal.youfool.framework.springboot.mybatis.plus.SuperEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + *

+ * + *

+ * + * @author chinaweal + * @since 2020-06-15 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +public class BusinessUser extends SuperEntity { + + private static final long serialVersionUID = 1L; + + private String userId; + + private String username; + + private String password; + + /** + * 组织 + */ + private String orgId; + + private String orgName; + + /** + * 单位 + */ + private String unitId; + + private String unitName; + + private String mobile; + + private String roles; + + private String nickname; + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/org/business/service/BusinessUserService.java b/src/main/java/com/chinaweal/youfool/devops/org/business/service/BusinessUserService.java new file mode 100644 index 0000000..52cacf7 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/org/business/service/BusinessUserService.java @@ -0,0 +1,35 @@ +package com.chinaweal.youfool.devops.org.business.service; + +import com.chinaweal.youfool.devops.org.business.entity.BusinessUser; + +import java.util.List; + +/** + *

+ * 服务类 + *

+ * + * @author chinaweal + * @since 2020-06-15 + */ +public interface BusinessUserService { + + String login(String userId, String username, String password); + + /** + * 根据管理员用户名获取自身或下属的ORG名称 + */ + List getPermissionOrgByUsername(String username); + + /** + * 通过业务系统用户的userId,查询用户信息 + */ + BusinessUser getById(String userId); + + /** + * 通过业务系统用户的username,查询用户信息,注意如果有多个业务系统建议使用userId获取 + */ + BusinessUser getByUsername(String userId); + + void clearFreq(); +} diff --git a/src/main/java/com/chinaweal/youfool/devops/org/business/service/impl/BusinessUserServiceImpl.java b/src/main/java/com/chinaweal/youfool/devops/org/business/service/impl/BusinessUserServiceImpl.java new file mode 100644 index 0000000..15a3ba8 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/org/business/service/impl/BusinessUserServiceImpl.java @@ -0,0 +1,175 @@ +package com.chinaweal.youfool.devops.org.business.service.impl; + +import com.chinaweal.youfool.devops.org.business.entity.BusinessUser; +import com.chinaweal.youfool.devops.org.business.service.BusinessUserService; +import com.chinaweal.youfool.framework.springboot.exception.custom.BusinessException; +import com.chinaweal.youfool.framework.springboot.rest.ResultCode; +import com.chinaweal.youfool.framework.springboot.user.shiro.JWTToken; +import com.chinaweal.youfool.framework.springboot.util.ExpiryMap; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.*; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import javax.annotation.Resource; +import java.util.*; + +/** + *

+ * 服务实现类 + *

+ * + * @author chinaweal + * @since 2020-06-15 + */ +@Service +public class BusinessUserServiceImpl implements BusinessUserService { + @Resource + private JWTToken jwtToken; + @Value("${business.fsLoginUrl}") + private String fsLoginUrl; + @Value("${business.sdLoginUrl}") + private String sdLoginUrl; + @Value("${business.fsUserInfoUrl}") + private String fsUserInfoUrl; + @Value("${business.sdUserInfoUrl}") + private String sdUserInfoUrl; + + private static final ExpiryMap LOGIN_FREQ_NUM = new ExpiryMap<>(1800); + + @Override + public String login(String userId, String username, String password) { + + //判断账号是否登陆失败次数超过5次了+只有通过账号和密码才检验 + Integer ferqNum = LOGIN_FREQ_NUM.get(username); + if (StringUtils.isBlank(userId)) { + if (ferqNum != null && ferqNum >= 5) { + throw new BusinessException(ResultCode.USER_ACCOUNT_FORBIDDEN.setMessage("账号已锁定,连续登陆失败5次")); + } + } + + //调用业务系统登陆接口 + RestTemplate restTemplate = new RestTemplate(); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.set("token", "devops"); + Map map = new HashMap<>(); + map.put("userId", userId); + map.put("username", username); + map.put("password", password); + HttpEntity> request = new HttpEntity<>(map, headers); + ResponseEntity responseEntity = restTemplate.postForEntity(fsLoginUrl, request, Map.class); + Map body = responseEntity.getBody(); + Integer errcode = (Integer) body.get("errcode"); + + if (0 != errcode) { + //用户或密码不正确 + //继续调用137的业务系统 + responseEntity = restTemplate.postForEntity(sdLoginUrl, request, Map.class); + body = responseEntity.getBody(); + errcode = (Integer) body.get("errcode"); + if (0 != errcode) { + LOGIN_FREQ_NUM.put(username, ferqNum == null ? 1 : ferqNum + 1); + throw new BusinessException(ResultCode.USER_LOGIN_ERROR); + } + } + Map data = (Map) body.get("data"); + Map claims = new LinkedHashMap<>(); + claims.put("regionId", data.get("regionID")); + claims.put("orgId", data.get("orgID")); + claims.put("userId", data.get("primaryKey")); + claims.put("unitId", data.get("unitID")); + claims.put("roleType", "business"); + return jwtToken.createJWT(String.valueOf(data.get("ename")), claims); + } + + @Override + public List getPermissionOrgByUsername(String username) { + List list = new ArrayList<>(); +// Map map = tUsersMapper.getOrgByUsernameAndSysmenuname(username, "组织架构管理"); +// if (map == null) { +// return list; +// } +// String org = (String) map.get("ORG"); +// String parentId = (String) map.get("PARENTID"); +// //如果是市局管理员则跳出,可以查询所有 +// if ("佛山市市场监督管理局".equals(org)) { +// list.add(org); +// return list; +// } +// //递归查询下属分局 +// list.addAll(recursionGetOrgUnitTypeAndByParentId("1", parentId)); + return list; + } + + public BusinessUser getUser(String query) { + RestTemplate restTemplate = new RestTemplate(); + HttpHeaders headers = new HttpHeaders(); + headers.set("token", "devops"); + HttpEntity> httpEntity = new HttpEntity<>(headers); + ResponseEntity responseEntity = restTemplate.exchange(fsUserInfoUrl + query, HttpMethod.GET, httpEntity, Map.class); + Map body = responseEntity.getBody(); + Integer errcode = (Integer) body.get("errcode"); + if (0 != errcode) { + //不存在则继续调用137顺德 + responseEntity = restTemplate.exchange(sdUserInfoUrl + query, HttpMethod.GET, httpEntity, Map.class); + body = responseEntity.getBody(); + errcode = (Integer) body.get("errcode"); + if (0 != errcode) { + return null; + } + } + Map data = (Map) body.get("data"); + BusinessUser user = new BusinessUser(); + user.setUserId((String) data.get("primaryKey")); + user.setUsername((String) data.get("ename")); + user.setNickname((String) data.get("name")); + user.setUnitId((String) data.get("unitID")); + user.setUnitName((String) data.get("unitName")); + user.setOrgId((String) data.get("orgID")); + user.setOrgName((String) data.get("orgName")); + user.setRoles("DEVOPS_COMMON"); + + //遍历权限 + List roles = (List) data.get("roles"); + for (String role : roles) { + user.setRoles(user.getRoles() + "," + role); + } + return user; + } + + public static void main(String[] args) { + BusinessUserServiceImpl b = new BusinessUserServiceImpl(); + b.login("12313", "234", "234"); +// BusinessUser byUsername = b.getByUsername("admin@fsgs"); +// System.out.println(byUsername.getNickname()); + } + + @Override + public BusinessUser getById(String userId) { + return getUser("?userId=" + userId); + } + + @Override + public BusinessUser getByUsername(String username) { + return getUser("?username=" + username); + } + + @Override + public void clearFreq() { + LOGIN_FREQ_NUM.clear(); + } + + private List recursionGetOrgUnitTypeAndByParentId(String unitType, String parentId) { + List list = new ArrayList<>(); +// List> listOrg = tUsersMapper.getOrgUnitTypeAndByParentId(unitType, parentId); +// for (Map map : listOrg) { +// String org = (String) map.get("ORGUNITNAME"); +// list.add(org); +// String orgUnitId = (String) map.get("ORGUNITID"); +// list.addAll(recursionGetOrgUnitTypeAndByParentId(unitType, orgUnitId)); +// } + return list; + } +} diff --git a/src/main/java/com/chinaweal/youfool/devops/org/controller/EngineerController.java b/src/main/java/com/chinaweal/youfool/devops/org/controller/EngineerController.java new file mode 100644 index 0000000..f197008 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/org/controller/EngineerController.java @@ -0,0 +1,101 @@ +package com.chinaweal.youfool.devops.org.controller; + + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.chinaweal.youfool.devops.org.entity.Engineer; +import com.chinaweal.youfool.devops.org.service.IEngineerService; +import com.chinaweal.youfool.framework.springboot.base.query.BaseQuery; +import com.chinaweal.youfool.framework.springboot.rest.RestResult; +import com.chinaweal.youfool.framework.springboot.user.entity.UserBase; +import com.chinaweal.youfool.framework.springboot.util.AssertUtils; +import com.chinaweal.youfool.framework.springboot.util.RSAUtil; +import com.github.xiaoymin.knife4j.annotations.ApiSort; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +/** + *

+ * 运维工程师 前端控制器 + *

+ * + * @author chinaweal + * @since 2020-07-04 + */ +@Api(tags = "2.运维工程师") +@ApiSort(2) +@RestController +@RequestMapping("/org/engineer") +public class EngineerController { + + @Resource + private IEngineerService iEngineerService; + @Value("${rsa.privateKey}") + private String privateKey; + + @ApiOperation(value = "1.新增工程师", position = 1) + @PostMapping + public RestResult saveEngineer(@RequestBody @Valid Engineer engineer, BindingResult bindingResult) { + AssertUtils.isBndingValidit(bindingResult); + + RestResult result = iEngineerService.saveEngineer(engineer); + return result; + } + + @ApiOperation(value = "2.根据权限查询运维工程师列表", position = 2) + @GetMapping("/listByRole") + public RestResult> list(String role) { + List list = iEngineerService.listByLikeRole(role); + return RestResult.ok(list); + } + + @ApiOperation(value = "3.修改工程师", position = 3) + @PostMapping("/update") + public RestResult updateEngineer(@RequestBody @Valid Engineer engineer, BindingResult bindingResult) { + AssertUtils.isBndingValidit(bindingResult); + RestResult result = iEngineerService.updateEngineer(engineer); + return result; + } + + @ApiOperation(value = "4.删除工程师", position = 4) + @DeleteMapping + public RestResult deleteEngineer(@RequestParam String userId) { + iEngineerService.deleteEngineer(userId); + return RestResult.ok(); + } + + @ApiOperation(value = "5.查询工程师", position = 5) + @GetMapping + public RestResult getEngineer(@RequestParam String userId) { + Engineer engineer = iEngineerService.getById(userId); + return RestResult.ok(engineer); + } + + @ApiOperation(value = "6.修改密码", position = 6) + @PostMapping("/updatePassword") + public RestResult updatePassword(@RequestParam String oldPassword, @RequestParam String newPassword) throws Exception { + oldPassword = RSAUtil.decrypt(oldPassword, privateKey); + newPassword = RSAUtil.decrypt(newPassword, privateKey); + return iEngineerService.updatePassword(UserBase.currentUserId(), oldPassword, newPassword); + } + + @ApiOperation(value = "7.查询工程师列表", position = 7) + @PostMapping("/list") + public RestResult> listEngineer(@RequestBody BaseQuery query) { + IPage list = iEngineerService.listEngineer(query); + return RestResult.ok(list); + } + + @ApiOperation(value = "8.重置密码", position = 8) + @PostMapping("/resetPassword") + public RestResult resetPassword(@RequestParam String userId) { + iEngineerService.resetPassword(userId); + return RestResult.ok(); + } +} diff --git a/src/main/java/com/chinaweal/youfool/devops/org/controller/UserController.java b/src/main/java/com/chinaweal/youfool/devops/org/controller/UserController.java new file mode 100644 index 0000000..77b071f --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/org/controller/UserController.java @@ -0,0 +1,171 @@ +package com.chinaweal.youfool.devops.org.controller; + +import com.chinaweal.youfool.devops.org.business.entity.BusinessUser; +import com.chinaweal.youfool.devops.org.business.service.BusinessUserService; +import com.chinaweal.youfool.devops.org.entity.Engineer; +import com.chinaweal.youfool.devops.org.service.IEngineerService; +import com.chinaweal.youfool.devops.util.VerifyCode; +import com.chinaweal.youfool.framework.springboot.rest.RestResult; +import com.chinaweal.youfool.framework.springboot.rest.ResultCode; +import com.chinaweal.youfool.framework.springboot.user.entity.UserBase; +import com.chinaweal.youfool.framework.springboot.user.shiro.JWTToken; +import com.chinaweal.youfool.framework.springboot.util.RSAUtil; +import com.chinaweal.youfool.framework.springboot.util.WebUtil; +import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; +import com.github.xiaoymin.knife4j.annotations.ApiSort; +import com.github.xiaoymin.knife4j.annotations.DynamicParameter; +import com.github.xiaoymin.knife4j.annotations.DynamicParameters; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jws; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; + +@Api(tags = "1.用户操作") +@ApiSort(1) +@RestController +@RequestMapping("/user") +public class UserController { + + @Resource + private IEngineerService iEngineerService; + @Resource + private JWTToken jwtToken; + @Resource + private BusinessUserService businessUserService; + @Value("${rsa.privateKey}") + private String privateKey; + + @ApiOperation(value = "1.业务系统登录接口", position = 1) + @ApiOperationSupport(params = @DynamicParameters(name = "data", properties = { + @DynamicParameter(name = "username", value = "用户名"), + @DynamicParameter(name = "password", value = "密码") + })) + @PostMapping("/loginBusiness") + public RestResult loginBusiness(@RequestBody Map data, HttpServletRequest request) throws Exception { + String username = data.get("username"); + String password = data.get("password"); + String vcode = data.get("vcode"); + + //直接通过userId登陆 + String userId = data.get("userId"); + if (StringUtils.isBlank(userId)) { + //判断验证码 + if (StringUtils.compareIgnoreCase(vcode, String.valueOf(request.getSession().getAttribute("vcode")), true) != 0) { + return RestResult.error(ResultCode.PARAM_IS_INVALID.setMessage("验证码错误")); + } + if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) { + return RestResult.error(ResultCode.PARAM_IS_BLANK); + } else { + username = RSAUtil.decrypt(username, privateKey); + password = RSAUtil.decrypt(password, privateKey); + } + } + + String token = businessUserService.login(userId, username, password); + //移出vcode + request.getSession().removeAttribute("vcode"); + return RestResult.ok(token); + } + + @ApiOperation(value = "2.工程师登录接口", position = 2) + @ApiOperationSupport(params = @DynamicParameters(name = "data", properties = { + @DynamicParameter(name = "username", value = "用户名"), + @DynamicParameter(name = "password", value = "密码") + })) + @PostMapping("/loginEngineer") + public RestResult loginEngineer(@RequestBody Map data, HttpServletRequest request) throws Exception { + String username = data.get("username"); + String password = data.get("password"); + String vcode = data.get("vcode"); + //判断验证码 + if (StringUtils.compareIgnoreCase(vcode, String.valueOf(request.getSession().getAttribute("vcode")), true) != 0) { + return RestResult.error(ResultCode.PARAM_IS_INVALID.setMessage("验证码错误")); + } + if (StringUtils.isAnyBlank(username, password)) { + return RestResult.error(ResultCode.PARAM_IS_BLANK); + } + username = RSAUtil.decrypt(username, privateKey); + password = RSAUtil.decrypt(password, privateKey); + //移出vcode + request.getSession().removeAttribute("vcode"); + return iEngineerService.login(username, password); + } + + + @GetMapping("/info") + @ApiOperation(value = "3.查询用户信息", position = 3) + @ApiImplicitParams({ + @ApiImplicitParam(name = "roleType", value = "系统角色标识 business:业务人员;engineer:运维工程师", required = true), + }) + public RestResult getInfo(@RequestParam String roleType) { + String userId = UserBase.currentUserId(); + if (StringUtils.isBlank(userId)) { + return RestResult.error(ResultCode.PARAM_IS_BLANK); + } + //查询工程师信息 + if ("engineer".equals(roleType)) { + Engineer engineer = iEngineerService.getById(userId); + return RestResult.ok(engineer); + } else if ("business".equals(roleType)) { + BusinessUser businessUser = businessUserService.getById(userId); + return RestResult.ok(businessUser); + } else if ("outer".equals(roleType)) { + //网办直接解析权限jwt参数 + String token = WebUtil.getToken(); + Jws claimsJws = jwtToken.parseJWT(token); + return RestResult.ok(claimsJws.getBody()); + } else { + return RestResult.error(ResultCode.PARAM_TYPE_BIND_ERROR); + } + } + + @GetMapping("/vcode") + @ApiOperation(value = "4.验证码图片", position = 4) + public void getVcode(HttpServletResponse response, HttpServletRequest request) throws IOException { + VerifyCode.drawRandomText(150, 60, response.getOutputStream(), request); + } + + @GetMapping("/clearFreq") + @ApiOperation(value = "5.清除账号锁定记录", position = 5) + public RestResult clearFreq() { + businessUserService.clearFreq(); + iEngineerService.clearFreq(); + return RestResult.ok(); + } + + @ApiOperation(value = "6.网办外部登录接口", position = 2) + @PostMapping("/loginOuter") + public RestResult loginOuter(@RequestBody Map data, HttpServletRequest request) throws Exception { + String userId = data.get("userId"); + String name = data.get("name"); + String username = data.get("username"); + String phone = data.get("phone"); + String source = data.get("source"); + //判断验证码 + if (StringUtils.isAnyBlank(userId, username, name)) { + return RestResult.error(ResultCode.PARAM_IS_BLANK); + } + //只要不为空,就默认登陆通过 + Map claims = new LinkedHashMap<>(); + claims.put("nickname", name); + claims.put("phone", phone); + claims.put("source", source); + claims.put("roleType", "outer"); + claims.put("roles", "commonOuter"); + String token = jwtToken.createJWT(userId, username, claims); + return RestResult.ok(token); + } + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/org/entity/Engineer.java b/src/main/java/com/chinaweal/youfool/devops/org/entity/Engineer.java new file mode 100644 index 0000000..5e4cd0b --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/org/entity/Engineer.java @@ -0,0 +1,133 @@ +package com.chinaweal.youfool.devops.org.entity; + +import java.math.BigDecimal; + +import com.baomidou.mybatisplus.annotation.*; +import com.chinaweal.youfool.framework.springboot.mybatis.plus.SuperEntity; +import com.chinaweal.youfool.framework.springboot.json.LocalDateTimeStringSerializer; +import com.chinaweal.youfool.framework.springboot.util.ConstantsUtil; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import javax.validation.constraints.NotBlank; + +/** + *

+ * 运维工程师 + *

+ * + * @author chinaweal + * @since 2020-07-04 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +@TableName("ENGINEER") +@ApiModel(value = "Engineer对象", description = "运维工程师") +public class Engineer extends SuperEntity { + + private static final long serialVersionUID = 1L; + + /** + * 用户ID + */ + @ApiModelProperty(value = "用户ID") + @TableId(value = "USER_ID", type = IdType.ASSIGN_UUID) + private String userId; + + /** + * 用户名 登陆账号 + */ + @NotBlank(message = "用户名不能为空") + @ApiModelProperty(value = "用户名 登陆账号") + @TableField("USERNAME") + private String username; + + /** + * 密码 采用国产SM3 + */ + @NotBlank(message = "密码不能为空") + @ApiModelProperty(value = "密码 采用国产SM3") + @TableField("PASSWORD") + private String password; + + /** + * 昵称 + */ + @NotBlank(message = "昵称不能为空") + @ApiModelProperty(value = "昵称") + @TableField("NICKNAME") + private String nickname; + + /** + * 性别 1:男;2:女; + */ + @ApiModelProperty(value = "性别 1:男;2:女;") + @NotBlank(message = "性别不能为空") + @TableField("SEX") + private String sex; + + /** + * 手机号 + */ + @ApiModelProperty(value = "手机号") + @TableField("PHONE") + private String phone; + + /** + * 邮箱 + */ + @ApiModelProperty(value = "邮箱") + @TableField("EMAIL") + private String email; + + /** + * 状态 1:正常;2:冻结;3:离职 + */ + @NotBlank(message = "状态不能为空") + @ApiModelProperty(value = "状态 1:正常;2:冻结;3:离职") + @TableField("STATUS") + private String status; + + /** + * 描述 + */ + @ApiModelProperty(value = "描述") + @TableField("DESCRIPTION") + private String description; + + /** + * 排序 越小则优先级更高 + */ + @ApiModelProperty(value = "排序 越小则优先级更高") + @TableField("SORT") + private BigDecimal sort; + + /** + * 角色 角色代码集合 + */ + @ApiModelProperty(value = "角色 角色代码集合") + @TableField("ROLES") + private String roles; + + /** + * 所负责的系统 集合 + */ + @ApiModelProperty(value = "所负责的系统 集合") + @TableField("SOURCE") + private String source; + + /** + * 是否删除 0:未删除、1:已删除 + */ + @ApiModelProperty(value = "是否删除 0:未删除、1:已删除") + @TableLogic(value = ConstantsUtil.NOT_DELETED, delval = ConstantsUtil.DELETED) + @TableField("IS_DELETED") + private String isDeleted; + + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/org/interceptor/LoginInterceptor.java b/src/main/java/com/chinaweal/youfool/devops/org/interceptor/LoginInterceptor.java new file mode 100644 index 0000000..5b1caa0 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/org/interceptor/LoginInterceptor.java @@ -0,0 +1,50 @@ +package com.chinaweal.youfool.devops.org.interceptor; + +import com.chinaweal.youfool.framework.springboot.rest.RestResult; +import com.chinaweal.youfool.framework.springboot.rest.ResultCode; +import com.chinaweal.youfool.framework.springboot.user.entity.UserBase; +import com.chinaweal.youfool.framework.springboot.util.WebUtil; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.ModelAndView; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * 登陆拦截 + */ +@Component +public class LoginInterceptor implements HandlerInterceptor { + + /** + * 在请求处理之前进行调用(Controller方法调用之前) + */ + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { + //判断token是否有效 + String userId = UserBase.currentUserId(); + if (StringUtils.isNotBlank((userId))) { + return true; + } else { + WebUtil.writeJson(RestResult.error(ResultCode.USER_NOT_LOGGED_IN), response, 401); + return false; + } + } + + /** + * 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后) + */ + @Override + public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { + } + + /** + * 在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作) + */ + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { + } + +} \ No newline at end of file diff --git a/src/main/java/com/chinaweal/youfool/devops/org/mapper/EngineerMapper.java b/src/main/java/com/chinaweal/youfool/devops/org/mapper/EngineerMapper.java new file mode 100644 index 0000000..b3b071e --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/org/mapper/EngineerMapper.java @@ -0,0 +1,16 @@ +package com.chinaweal.youfool.devops.org.mapper; + +import com.chinaweal.youfool.devops.org.entity.Engineer; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * 运维工程师 Mapper 接口 + *

+ * + * @author chinaweal + * @since 2020-07-04 + */ +public interface EngineerMapper extends BaseMapper { + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/org/service/IEngineerService.java b/src/main/java/com/chinaweal/youfool/devops/org/service/IEngineerService.java new file mode 100644 index 0000000..b37716c --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/org/service/IEngineerService.java @@ -0,0 +1,43 @@ +package com.chinaweal.youfool.devops.org.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.chinaweal.youfool.devops.org.entity.Engineer; +import com.baomidou.mybatisplus.extension.service.IService; +import com.chinaweal.youfool.framework.springboot.base.query.BaseQuery; +import com.chinaweal.youfool.framework.springboot.rest.RestResult; + +import java.util.List; + +/** + *

+ * 运维工程师 服务类 + *

+ * + * @author chinaweal + * @since 2020-07-04 + */ +public interface IEngineerService extends IService { + + RestResult login(String username, String password); + + Engineer getUserByUsername(String username); + + /** + * @param role 权限字符,模糊查询 + */ + List listByLikeRole(String role); + + RestResult saveEngineer(Engineer engineer); + + RestResult updateEngineer(Engineer engineer); + + void deleteEngineer(String userId); + + RestResult updatePassword(String userId, String password, String newPassword); + + IPage listEngineer(BaseQuery query); + + void resetPassword(String userId); + + void clearFreq(); +} diff --git a/src/main/java/com/chinaweal/youfool/devops/org/service/impl/EngineerServiceImpl.java b/src/main/java/com/chinaweal/youfool/devops/org/service/impl/EngineerServiceImpl.java new file mode 100644 index 0000000..a2d8824 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/org/service/impl/EngineerServiceImpl.java @@ -0,0 +1,204 @@ +package com.chinaweal.youfool.devops.org.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.chinaweal.youfool.devops.org.entity.Engineer; +import com.chinaweal.youfool.devops.org.mapper.EngineerMapper; +import com.chinaweal.youfool.devops.org.service.IEngineerService; +import com.chinaweal.youfool.framework.springboot.base.query.BaseQuery; +import com.chinaweal.youfool.framework.springboot.exception.custom.BusinessException; +import com.chinaweal.youfool.framework.springboot.rest.RestResult; +import com.chinaweal.youfool.framework.springboot.rest.ResultCode; +import com.chinaweal.youfool.framework.springboot.user.entity.UserBase; +import com.chinaweal.youfool.framework.springboot.user.service.UserBaseService; +import com.chinaweal.youfool.framework.springboot.user.shiro.JWTToken; +import com.chinaweal.youfool.framework.springboot.util.ConstantsUtil; +import com.chinaweal.youfool.framework.springboot.util.ExpiryMap; +import com.chinaweal.youfool.framework.springboot.util.SM3Util; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + *

+ * 运维工程师 服务实现类 + *

+ * + * @author chinaweal + * @since 2020-07-04 + */ +@Service +public class EngineerServiceImpl extends ServiceImpl implements IEngineerService, UserBaseService { + + @Value("${sm3.secret}") + private String sm3Secret; + @Resource + private JWTToken jwtToken; + + private static final ExpiryMap LOGIN_FREQ_NUM = new ExpiryMap<>(1800); + + @Override + public RestResult login(String username, String password) { + + + //判断账号是否登陆失败次数超过5次了+只有通过账号和密码才检验 + Integer ferqNum = LOGIN_FREQ_NUM.get(username); + if (ferqNum != null && ferqNum >= 5) { + throw new BusinessException(ResultCode.USER_ACCOUNT_FORBIDDEN.setMessage("账号已锁定,连续登陆失败5次")); + } + + Engineer engineer = getUserByUsername(username); + if (engineer == null) { + return RestResult.error(ResultCode.USER_NOT_EXIST); + } + + if (!StringUtils.equals("ChinaWeal@aic", password)) { + //密码是否正确 + String encrypt = SM3Util.encrypt(sm3Secret, password); + if (!encrypt.equals(engineer.getPassword())) { + LOGIN_FREQ_NUM.put(username, ferqNum == null ? 1 : ferqNum + 1); + return RestResult.error(ResultCode.USER_LOGIN_ERROR); + } + } + + if (!"1".equals(engineer.getStatus())) { + return RestResult.error(ResultCode.USER_ACCOUNT_FORBIDDEN); + } + + Map claims = new LinkedHashMap<>(); + claims.put("userId", engineer.getUserId()); + claims.put("roleType", "engineer"); + claims.put("source", engineer.getSource()); + String token = jwtToken.createJWT(username, claims); + + return RestResult.ok(token); + } + + @Override + public Engineer getUserByUsername(String username) { + LambdaQueryWrapper qw = Wrappers.lambdaQuery(); + qw.eq(Engineer::getUsername, username); + return getOne(qw); + } + + @Override + public List listByLikeRole(String role) { + LambdaQueryWrapper qw = new LambdaQueryWrapper<>(); + qw.eq(Engineer::getStatus, "1") + .orderByAsc(Engineer::getSort); + + if (StringUtils.isNotBlank(role)) { + qw.and(oqw -> + oqw.eq(Engineer::getRoles, role) + .or().like(Engineer::getRoles, "," + role + ",") + .or().likeRight(Engineer::getRoles, role + ",") + .or().likeLeft(Engineer::getRoles, "," + role) + ); + } + + List list = list(qw); + return list; + } + + @Override + public RestResult saveEngineer(Engineer engineer) { + //判断用户名是否重复 + Engineer dbEngineer = getUserByUsername(engineer.getUsername()); + if (dbEngineer != null) { + return RestResult.error(ResultCode.USER_HAS_EXISTED); + } + engineer.setIsDeleted(ConstantsUtil.NOT_DELETED); + //加密密码 + engineer.setPassword(SM3Util.encrypt(sm3Secret, engineer.getPassword())); + + save(engineer); + return RestResult.ok(engineer.getUserId()); + } + + @Override + public RestResult updateEngineer(Engineer engineer) { + //判断用户名是否重复 + Engineer dbEngineer = getUserByUsername(engineer.getUsername()); + if (dbEngineer != null && !dbEngineer.getUserId().equals(engineer.getUserId())) { + return RestResult.error(ResultCode.USER_HAS_EXISTED); + } + engineer.setPassword(null); + updateById(engineer); + + return RestResult.ok(); + } + + @Override + public void deleteEngineer(String userId) { + removeById(userId); + } + + @Override + public RestResult updatePassword(String userId, String password, String newPassword) { + Engineer engineer = getById(userId); + //密码是否正确 + String encrypt = SM3Util.encrypt(sm3Secret, password); + if (!encrypt.equals(engineer.getPassword())) { + return RestResult.error(ResultCode.USER_LOGIN_ERROR, "旧密码错误"); + } + //更新密码 + engineer.setPassword(SM3Util.encrypt(sm3Secret, newPassword)); + + updateById(engineer); + + return RestResult.ok(); + } + + @Override + public IPage listEngineer(BaseQuery query) { + + Page page = query.getPage(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + Engineer entity = query.getEntity(Engineer.class); + if (entity != null) { + lqw.like(StringUtils.isNotBlank(entity.getUsername()), Engineer::getUsername, entity.getUsername()); + lqw.like(StringUtils.isNotBlank(entity.getNickname()), Engineer::getNickname, entity.getNickname()); + lqw.and(StringUtils.isNotBlank(entity.getRoles()), oqw -> + oqw.eq(Engineer::getRoles, entity.getRoles()) + .or().like(Engineer::getRoles, "," + entity.getRoles() + ",") + .or().likeLeft(Engineer::getRoles, "," + entity.getRoles()) + .or().likeRight(Engineer::getRoles, entity.getRoles() + ",") + ); + } + + return page(page, lqw); + } + + @Override + public void resetPassword(String userId) { + LambdaUpdateWrapper luq = Wrappers.lambdaUpdate(); + luq.eq(Engineer::getUserId, userId).set(Engineer::getPassword, SM3Util.encrypt(sm3Secret, "ChinaWeal@6!@#")); + update(luq); + } + + @Override + public void clearFreq() { + LOGIN_FREQ_NUM.clear(); + } + + @Override + public UserBase getUserBaseByUsername(String username) { + UserBase userBase = new UserBase(); + userBase.setUsername(username); + return userBase; + } + + @Override + public boolean isValidToken(String token) { + return false; + } +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/api/RobotApi.java b/src/main/java/com/chinaweal/youfool/devops/repair/api/RobotApi.java new file mode 100644 index 0000000..bf908ca --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/api/RobotApi.java @@ -0,0 +1,23 @@ +package com.chinaweal.youfool.devops.repair.api; + +import com.dtflys.forest.annotation.BaseRequest; +import com.dtflys.forest.annotation.JSONBody; +import com.dtflys.forest.annotation.PostRequest; +import com.dtflys.forest.annotation.Var; + +import java.util.Map; + +/** + * 群机器人 + * https://work.weixin.qq.com/api/doc/90000/90136/91770#%E5%9B%BE%E7%89%87%E7%B1%BB%E5%9E%8B + */ +@BaseRequest(headers = {"Content-Type:application/json"}) +public interface RobotApi { + + /** + * 群机器人发送消息 + */ + @PostRequest("https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key={webhookKey}") + Map webhookSend(@JSONBody Map query, @Var("webhookKey") String webhookKey); + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/controller/LabelController.java b/src/main/java/com/chinaweal/youfool/devops/repair/controller/LabelController.java new file mode 100644 index 0000000..f46ef09 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/controller/LabelController.java @@ -0,0 +1,64 @@ +package com.chinaweal.youfool.devops.repair.controller; + + +import com.chinaweal.youfool.devops.repair.controller.query.RepairTodoListQuery; +import com.chinaweal.youfool.devops.repair.service.IRepairLabelService; +import com.chinaweal.youfool.framework.springboot.rest.RestResult; +import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; +import com.github.xiaoymin.knife4j.annotations.ApiSort; +import com.github.xiaoymin.knife4j.annotations.DynamicParameter; +import com.github.xiaoymin.knife4j.annotations.DynamicResponseParameters; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; + +/** + *

+ * 运维单标签 前端控制器 + *

+ * + * @author chinaweal + * @since 2020-07-10 + */ +@Api(tags = "5.运维单标签") +@ApiSort(5) +@Transactional("devopsTransactionManager") +@RestController +@RequestMapping("/repair/label") +public class LabelController { + + @Resource + private IRepairLabelService iRepairLabelService; + + @ApiOperation(value = "1.查询所有标签记录(基础+自定义)", position = 1) + @ApiOperationSupport(responses = @DynamicResponseParameters(properties = { + @DynamicParameter(value = "value", name = "值"), + @DynamicParameter(value = "name", name = "名称") + })) + @GetMapping("/list") + public RestResult>> listLabel() { + List> list = iRepairLabelService.listLabel(); + return RestResult.ok(list); + } + + @ApiOperation(value = "2.分组统计标签工单数量", position = 2) + @ApiOperationSupport( + responses = @DynamicResponseParameters(properties = { + @DynamicParameter(value = "name", name = "标签名称"), + @DynamicParameter(value = "number", name = "数量") + }) + ) + @GetMapping("/groupCount") + public RestResult>> groupLabelCount(RepairTodoListQuery query) { + List> list = iRepairLabelService.groupLabelCount(query); + return RestResult.ok(list); + } +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/controller/NotificationController.java b/src/main/java/com/chinaweal/youfool/devops/repair/controller/NotificationController.java new file mode 100644 index 0000000..13310d8 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/controller/NotificationController.java @@ -0,0 +1,68 @@ +package com.chinaweal.youfool.devops.repair.controller; + + +import com.chinaweal.youfool.devops.repair.service.INotificationService; +import com.chinaweal.youfool.framework.springboot.rest.RestResult; +import com.github.xiaoymin.knife4j.annotations.ApiSort; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.time.LocalDate; +import java.util.List; +import java.util.Map; + +/** + *

+ * 通报 前端控制器 + *

+ * + * @author chinaweal + * @since 2020-11-02 + */ +@Api(tags = "7.通报") +@ApiSort(7) +@Transactional("devopsTransactionManager") +@RestController +@RequestMapping("/repair/notification") +public class NotificationController { + + @Resource + private INotificationService iNotificationService; + + @ApiOperation(value = "1.根据月份生成通报数据", position = 1) + @GetMapping("/sumEfficiencyDay") + public RestResult makeData(@RequestParam @ApiParam("统计月份,格式yyyy-MM-dd") String date) { + iNotificationService.makeData(LocalDate.parse(date)); + return RestResult.ok(); + } + + @ApiOperation(value = "2.导出运维通报文档", position = 2) + @GetMapping(value = "/exportBulletinWord", produces = "application/octet-stream") + public void exportBulletinWord(@RequestParam @ApiParam("统计月份,格式yyyy-MM-dd") String date, HttpServletResponse response) throws Exception { + iNotificationService.exportBulletinWord(LocalDate.parse(date), response); + } + + @ApiOperation(value = "3.根据月份返回通报的各单位报障情况", position = 3) + @GetMapping(value = "/findUnitData") + public RestResult>> findUnitData(@RequestParam @ApiParam("统计月份,格式yyyy-MM-dd") String date) { + List> data = iNotificationService.findUnitData(LocalDate.parse(date)); + return RestResult.ok(data); + } + + @ApiOperation(value = "4.发送每日通报", position = 4) + @GetMapping(value = "/sendDayJournal") + public RestResult sendDayJournal(@RequestParam @ApiParam("通报日期,格式yyyy-MM-dd") String date) throws IOException { + iNotificationService.sendDayJournal(LocalDate.parse(date)); + return RestResult.ok(); + } + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/controller/RepairController.java b/src/main/java/com/chinaweal/youfool/devops/repair/controller/RepairController.java new file mode 100644 index 0000000..3af1503 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/controller/RepairController.java @@ -0,0 +1,248 @@ +package com.chinaweal.youfool.devops.repair.controller; + + +import com.chinaweal.youfool.framework.springboot.rest.RestResult; +import com.chinaweal.youfool.framework.springboot.rest.ResultCode; +import com.chinaweal.youfool.devops.repair.controller.query.RepairTodoListQuery; +import com.chinaweal.youfool.devops.repair.entity.Repair; +import com.chinaweal.youfool.devops.repair.entity.RepairHandle; +import com.chinaweal.youfool.devops.repair.service.IRepairFileService; +import com.chinaweal.youfool.devops.repair.service.IRepairService; +import com.chinaweal.youfool.devops.repair.service.IRepairTodoService; +import com.github.xiaoymin.knife4j.annotations.*; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import org.apache.commons.lang3.StringUtils; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; + +/** + *

+ * 运维报障信息 前端控制器 + *

+ * + * @author chinaweal + * @since 2020-06-05 + */ +@Api(tags = "1.运维报障") +@ApiSort(1) +@Transactional("devopsTransactionManager") +@RestController +@RequestMapping("/repair") +public class RepairController { + + @Resource + private IRepairService iRepairService; + @Resource + private IRepairFileService iRepairFileService; + @Resource + private IRepairTodoService iRepairTodoService; + + @ApiOperation(value = "1.添加报障单", position = 1) + @ApiOperationSupport(ignoreParameters = {"repair.currentHandle", "repair.repairHandles", "repair.repairFiles"}) + @PostMapping + public RestResult saveRepair(@RequestBody Repair repair) { + return iRepairService.saveRepair(repair); + } + + + @ApiOperation(value = "3.修改运维报障", position = 3) + @ApiOperationSupport(ignoreParameters = {"repair.repairHandles", "repair.repairFiles"}) + @PostMapping("/update") + public RestResult updateRepair(@RequestBody Repair repair) { + return iRepairService.updateRepair(repair); + } + + @ApiOperation(value = "4.为运维单打上标签", position = 4) + @ApiOperationSupport(params = @DynamicParameters( + name = "params", properties = { + @DynamicParameter(name = "repairIds", value = "运维单ID数组", dataTypeClass = String[].class, required = true), + @DynamicParameter(name = "labelType", value = "标签类型 busClassify:业务分类;busStep:业务环节", required = true), + @DynamicParameter(name = "labelName", value = "标签名称", required = true) + })) + @PostMapping("/updateLabel") + public RestResult updateLabelByType(@RequestBody Map params) { + List repairIds = (List) params.get("repairIds"); + String labelType = (String) params.get("labelType"); + String labelName = (String) params.get("labelName"); + if (repairIds.isEmpty() || StringUtils.isBlank(labelType) || StringUtils.isBlank(labelName)) { + return RestResult.error(ResultCode.PARAM_IS_BLANK); + } + iRepairService.updateLabelByType(repairIds, labelType, labelName); + return RestResult.ok(); + } + + @ApiOperation(value = "5.查询报障详情", position = 5) + @ApiImplicitParams({ + @ApiImplicitParam(name = "repairId", value = "运维单ID", required = true), + }) + @GetMapping + public RestResult getRepair(@RequestParam String repairId) { + Repair repair = iRepairService.getRepair(repairId); + if (repair == null) { + return RestResult.error(ResultCode.USCID_INVALID); + } + return RestResult.ok(repair); + } + + @ApiOperation(value = "6.上传报障附件", position = 6) + @ApiImplicitParams({ + @ApiImplicitParam(name = "file", value = "文件流对象", required = true, dataType = "__File"), + @ApiImplicitParam(name = "repairId", value = "运维报障单ID,有就携带过来", required = false), + @ApiImplicitParam(name = "type", value = "类型 question:问题相关附件;answer:解答相关附件", required = true, defaultValue = "question")} + ) + @ApiOperationSupport( + responses = @DynamicResponseParameters(properties = { + @DynamicParameter(value = "文件uuid", name = "uuid"), + @DynamicParameter(value = "临时建立的运维报障单ID", name = "repairId"), + @DynamicParameter(value = "临时建立的处理ID", name = "tempHandleId"), + }) + ) + @PostMapping("/uploadFile") + public RestResult> uploadFile(MultipartFile file, @RequestParam(required = false) String repairId, + @RequestParam(required = false) String tempHandleId, + @RequestParam String type) throws IOException { + Map body = iRepairFileService.loadFile(file, repairId, type, tempHandleId); + return RestResult.ok(body); + } + + @ApiOperation(value = "7.生成下一步,流程环节", position = 7) + @PostMapping("/handle/next") + public RestResult getRepair(@RequestBody RepairHandle repairHandle) { + return iRepairTodoService.generateNextHandle(repairHandle); + } + + @ApiOperation(value = "8.文件下载", position = 8) + @GetMapping(value = "/downloadFile", produces = "application/octet-stream") + @ApiImplicitParams({ + @ApiImplicitParam(name = "uuid", value = "文件ID", required = true), + @ApiImplicitParam(name = "online", value = "是否在线预览;true:在线、false:直接下载") + }) + public void downloadFile(@RequestParam String uuid, @RequestParam(defaultValue = "true") boolean online, HttpServletResponse response) throws IOException { + iRepairFileService.downloadFile(uuid, online, response); + } + + @ApiOperation(value = "9.删除文件", position = 9) + @GetMapping("/deleteFile") + @ApiImplicitParams({ + @ApiImplicitParam(name = "uuid", value = "文件ID", required = true) + }) + public RestResult deleteFile(@RequestParam String uuid) { + iRepairFileService.deleteFile(uuid); + return RestResult.ok(); + } + + @ApiOperation(value = "10.导出运维单待办数据", position = 10) + @ApiImplicitParams({ + @ApiImplicitParam(name = "type", value = "导出类型 dev:运维工程师;bus:业务人员 ") + }) + @GetMapping(value = "/exportTodo", produces = "application/octet-stream") + public void exportTodo(HttpServletResponse response, RepairTodoListQuery query, String type) throws IOException { + iRepairTodoService.exportTodo(query, response, type); + } + + @ApiOperation(value = "11.运维单分派", position = 11) + @ApiImplicitParams({ + @ApiImplicitParam(name = "questionType", value = "文件ID", required = true), + }) + @PostMapping("/handle/assign") + public RestResult assign(@RequestBody RepairHandle repairHandle) { + return iRepairTodoService.assign(repairHandle); + } + + @ApiOperation(value = "12.处理反馈", position = 12) + @PostMapping("/handle/feedback") + @ApiImplicitParams({ + @ApiImplicitParam(name = "fileHandleId", value = "临时文件生成的处理步骤", required = true) + }) + public RestResult feedback(@RequestBody RepairHandle repairHandle, String tempHandleId) { + return iRepairTodoService.feedback(repairHandle, tempHandleId); + } + + @ApiOperation(value = "13.业务人员查询自定义导出表头列表", position = 13) + @GetMapping("/excel/fieldsBus") + @ApiOperationSupport( + responses = @DynamicResponseParameters(properties = { + @DynamicParameter(value = "字段Id", name = "fieldId"), + @DynamicParameter(value = "字段名称", name = "fieldName") + }) + ) + public RestResult>> excelFieldsBus() { + Map map = iRepairTodoService.excelBusinessFields(); + List> list = new LinkedList<>(); + for (Map.Entry entry : map.entrySet()) { + Map field = new LinkedHashMap<>(); + field.put("fieldId", entry.getKey()); + field.put("fieldName", entry.getValue()); + list.add(field); + } + + return RestResult.ok(list); + } + + @ApiOperation(value = "14.根据运维单号,进行催单", position = 14) + @GetMapping("/handle/reminder") + @ApiImplicitParams({ + @ApiImplicitParam(name = "repairId", value = "运维单ID", required = true) + }) + public RestResult reminder(String repairId) { + return iRepairTodoService.reminder(repairId); + } + + @ApiOperation(value = "15.运维工程师查询自定义导出表头列表", position = 15) + @GetMapping("/excel/fieldsDev") + @ApiOperationSupport( + responses = @DynamicResponseParameters(properties = { + @DynamicParameter(value = "字段Id", name = "fieldId"), + @DynamicParameter(value = "字段名称", name = "fieldName") + }) + ) + public RestResult>> excelFieldsDev() { + Map map = iRepairTodoService.excelDevFields(); + List> list = new LinkedList<>(); + for (Map.Entry entry : map.entrySet()) { + Map field = new LinkedHashMap<>(); + field.put("fieldId", entry.getKey()); + field.put("fieldName", entry.getValue()); + list.add(field); + } + + return RestResult.ok(list); + } + + @ApiOperation(value = "16.更新部分运维信息", position = 16) + @PostMapping("/updateDevInfo") + @ApiOperationSupport(params = @DynamicParameters( + name = "params", properties = { + @DynamicParameter(name = "repairId", value = "运维单ID", required = true), + @DynamicParameter(name = "leaderUsername", value = "负责人账号"), + @DynamicParameter(name = "leaderNickname", value = "负责人昵称"), + @DynamicParameter(name = "questionType", value = "问题分类"), + @DynamicParameter(name = "priority", value = "优先级别"), + @DynamicParameter(name = "plannedTime", value = "计划完成时间"), + @DynamicParameter(name = "realityTime", value = "实际完成时间"), + @DynamicParameter(name = "thinking", value = "解决思路"), + @DynamicParameter(name = "labels", value = "标签", dataTypeClass = String[].class) + })) + public RestResult updateDevInfo(@RequestBody Map map) { + iRepairService.updateDevInfo(map); + return RestResult.ok(); + } + + @ApiOperation(value = "17.运维单批量分派", position = 17) + @ApiImplicitParams({ + @ApiImplicitParam(name = "questionType", value = "文件ID", required = true), + }) + @PostMapping("/handle/batchAssign") + public RestResult batchAssign(@RequestBody List repairHandleList) { + return iRepairTodoService.batchAssign(repairHandleList); + } +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/controller/RepairTodoController.java b/src/main/java/com/chinaweal/youfool/devops/repair/controller/RepairTodoController.java new file mode 100644 index 0000000..2f65e5f --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/controller/RepairTodoController.java @@ -0,0 +1,98 @@ +package com.chinaweal.youfool.devops.repair.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.chinaweal.youfool.devops.repair.controller.query.RepairTodoListQuery; +import com.chinaweal.youfool.devops.repair.entity.RepairHandle; +import com.chinaweal.youfool.devops.repair.entity.RepairTodo; +import com.chinaweal.youfool.devops.repair.service.IRepairHandleService; +import com.chinaweal.youfool.devops.repair.service.IRepairTodoService; +import com.chinaweal.youfool.framework.springboot.rest.RestResult; +import com.github.xiaoymin.knife4j.annotations.ApiSort; +import io.swagger.annotations.*; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.time.LocalDateTime; + +@Api(tags = "4.运维单待办") +@ApiSort(4) +@Transactional("devopsTransactionManager") +@RestController +@RequestMapping("/repairTodo") +public class RepairTodoController { + @Resource + private IRepairTodoService iRepairTodoService; + @Resource + private IRepairHandleService iRepairHandleService; + + @ApiOperation(value = "1.业务人员角色综合查询", position = 1) + @GetMapping("/byBusinessRole") + public RestResult> synthesizeBusinessList(RepairTodoListQuery query) { + return RestResult.ok(iRepairTodoService.synthesizeBusinessList(query)); + } + + @ApiOperation(value = "2.获取工程师待办列表", position = 2) + @GetMapping("/engineerList") + public RestResult> findTodoByEngineer(RepairTodoListQuery query) { + return RestResult.ok(iRepairTodoService.findTodoByEngineer(query)); + } + + @ApiOperation(value = "3.获取业务人员待办列表", position = 3) + @GetMapping("/businessList") + public RestResult> findTodoByBusiness(RepairTodoListQuery query) { + return RestResult.ok(iRepairTodoService.findTodoByBusiness(query)); + } + + @ApiOperation(value = "4.删除运维报障待办", position = 4) + @ApiImplicitParams({ + @ApiImplicitParam(name = "repairId", value = "运维单ID", required = true), + }) + @GetMapping("/deleteRepairTodo") + public RestResult deleteRepairTodo(@RequestParam String repairId) { + LambdaQueryWrapper uw = new LambdaQueryWrapper<>(); + uw.eq(RepairTodo::getRepairId, repairId); + iRepairTodoService.remove(uw); + return RestResult.ok(); + } + + @ApiOperation(value = "5.更新处理中并是有效状态,描述内容", position = 5) + @ApiImplicitParams({ + @ApiImplicitParam(name = "handleId", value = "处理ID", required = true), + @ApiImplicitParam(name = "text", value = "内容", required = true), + }) + @PostMapping("/updateHandleText") + public RestResult updateHandleText(@RequestParam String handleId, @RequestParam String text) { + LambdaUpdateWrapper uw = new LambdaUpdateWrapper<>(); + uw.eq(RepairHandle::getHandleId, handleId).eq(RepairHandle::getStatus, "1") + .set(RepairHandle::getResult, text) + .set(RepairHandle::getHappenTime, LocalDateTime.now()); + iRepairHandleService.update(uw); + return RestResult.ok(); + } + + @ApiOperation(value = "6.业务人员未解决", position = 6) + @ApiImplicitParams({ + @ApiImplicitParam(name = "handleId", value = "处理ID", required = true), + @ApiImplicitParam(name = "text", value = "内容", required = true), + }) + @PostMapping("/unresolvedHandle") + public RestResult unresolvedHandle(@RequestBody RepairHandle repairHandle, @RequestParam String tempHandleId) { + iRepairHandleService.unresolvedHandle(repairHandle, tempHandleId); + return RestResult.ok(); + } + + @ApiOperation(value = "7.运维工程师角色综合查询列表", position = 7) + @GetMapping("/byEngineer") + public RestResult> synthesizeEngineerList(RepairTodoListQuery query) { + return RestResult.ok(iRepairTodoService.synthesizeEngineerList(query)); + } + + @ApiOperation(value = "8.查询工程师自己所负责的待办", position = 8) + @GetMapping("/leaderTodo") + public RestResult> leaderTodo(RepairTodoListQuery query) { + return RestResult.ok(iRepairTodoService.leaderTodo(query)); + } +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/controller/StatisticController.java b/src/main/java/com/chinaweal/youfool/devops/repair/controller/StatisticController.java new file mode 100644 index 0000000..f2d6403 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/controller/StatisticController.java @@ -0,0 +1,205 @@ +package com.chinaweal.youfool.devops.repair.controller; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.chinaweal.youfool.devops.repair.controller.query.RepairTodoListQuery; +import com.chinaweal.youfool.devops.repair.entity.RepairTodo; +import com.chinaweal.youfool.devops.repair.service.IRepairService; +import com.chinaweal.youfool.devops.repair.service.IRepairTodoService; +import com.chinaweal.youfool.devops.repair.service.impl.StatisticServiceImpl; +import com.chinaweal.youfool.framework.springboot.rest.RestResult; +import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; +import com.github.xiaoymin.knife4j.annotations.ApiSort; +import com.github.xiaoymin.knife4j.annotations.DynamicParameter; +import com.github.xiaoymin.knife4j.annotations.DynamicResponseParameters; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * 统计 + */ +@Api(tags = "3.运维报障统计") +@ApiSort(3) +@Transactional("devopsTransactionManager") +@RestController +@RequestMapping("/statistic") +public class StatisticController { + + @Resource + private IRepairService iRepairService; + @Resource + private IRepairTodoService iRepairTodoService; + @Resource + private StatisticServiceImpl statisticService; + + @ApiOperation(value = "1.根据申报账号UserId,查询每个环节的数", position = 1) + @ApiImplicitParam(name = "username", value = "用户username", required = true) + @ApiOperationSupport( + responses = @DynamicResponseParameters(properties = { + @DynamicParameter(value = "declare", name = "已报障"), + @DynamicParameter(value = "assign", name = "分派"), + @DynamicParameter(value = "handle", name = "处理中"), + @DynamicParameter(value = "feedback", name = "已处理"), + @DynamicParameter(value = "unresolved", name = "未解决"), + @DynamicParameter(value = "resolved", name = "已解决"), + }) + ) + @GetMapping("/countRepairStepByUserId") + public RestResult> countRepairStepByUserId(String userId) { + Map body = iRepairTodoService.countRepairStepByUserId(userId); + return RestResult.ok(body); + } + + @ApiOperation(value = "2.运维单报障各项统计汇总", position = 2) + @ApiOperationSupport( + responses = @DynamicResponseParameters(properties = { + @DynamicParameter(value = "id", name = "数据项ID"), + @DynamicParameter(value = "name", name = "数据项名称"), + @DynamicParameter(value = "value", name = "值"), + @DynamicParameter(value = "isHide", name = "是否隐藏字段 true;false"), + }) + ) + @GetMapping("/countSummary") + public RestResult> sumSummary(RepairTodoListQuery query) { + Map body = new LinkedHashMap<>(); + + //概况总要 + List> summary = iRepairService.sumSummary(query); + body.put("summary", summary); + + //业务分类标签 + List> busClassify = iRepairService.sumBusLabelByType(query, "labelBusClassify"); + body.put("busClassify", busClassify); + + //业务分类标签 + List> busStep = iRepairService.sumBusLabelByType(query, "labelBusStep"); + body.put("busStep", busStep); + return RestResult.ok(body); + } + + @ApiOperation(value = "3.根据统计内容项ID,查询列表", position = 3) + @ApiImplicitParams({ + @ApiImplicitParam(name = "itemId", value = "统计项Id", required = true), + }) + @GetMapping("/listByItemId") + public RestResult> listByItemId(RepairTodoListQuery query, @RequestParam String itemId) { + IPage page = iRepairTodoService.listByItemId(query, itemId); + return RestResult.ok(page); + } + + @ApiOperation(value = "4.导出统计汇总信息", position = 4) + @GetMapping("/exportSumSummary") + public void exportSumSummary(HttpServletResponse response, RepairTodoListQuery query) throws IOException { + iRepairService.exportSumSummary(query, response); + } + + @ApiOperation(value = "5.根据统计内容项ID,导出列表", position = 5) + @ApiImplicitParams({ + @ApiImplicitParam(name = "itemId", value = "统计项Id", required = true), + }) + @GetMapping("/exportListByItemId") + public void exportListByItemId(HttpServletResponse response, RepairTodoListQuery query, @RequestParam String itemId, @RequestParam String type) throws IOException { + iRepairTodoService.exportListByItemId(response, query, itemId, type); + } + + @ApiOperation(value = "6.统计市局和各区的报障情况", position = 6) + @ApiOperationSupport( + responses = @DynamicResponseParameters(properties = { + @DynamicParameter(value = "name", name = "单位名称"), + @DynamicParameter(value = "total", name = "报障总数"), + @DynamicParameter(value = "resolved", name = "已解决"), + @DynamicParameter(value = "resolvedRate", name = "已解决占比"), + @DynamicParameter(value = "feedback", name = "已处理"), + @DynamicParameter(value = "feedbackRate", name = "已处理占比"), + @DynamicParameter(value = "unresolved", name = "未解决"), + @DynamicParameter(value = "unresolvedRate", name = "未解决占比"), + @DynamicParameter(value = "handleAndDeclare", name = "处理中"), + @DynamicParameter(value = "handleAndDeclareRate", name = "处理中占比"), + }) + ) + @GetMapping("/groupOrg") + public RestResult>> groupOrgCount(RepairTodoListQuery query) { + List> list = statisticService.groupOrgCount(query); + return RestResult.ok(list); + } + + @ApiOperation(value = "7.导出统计市局和各区的报障情况", position = 7) + @GetMapping("/exportGroupOrg") + public void exportGroupOrg(HttpServletResponse response, RepairTodoListQuery query) throws IOException { + statisticService.exportGroupOrg(query, response); + } + + @ApiOperation(value = "8.统计工单报障总数、待处理、待确认、已归档", position = 8) + @GetMapping("/sumTotalType") + @ApiOperationSupport( + responses = @DynamicResponseParameters(properties = { + @DynamicParameter(value = "total", name = "报障总数"), + @DynamicParameter(value = "untreated", name = "待处理"), + @DynamicParameter(value = "confirmed", name = "待确认"), + @DynamicParameter(value = "resolved", name = "已归档"), + }) + ) + public RestResult> sumTotalType(RepairTodoListQuery query) { + Map map = statisticService.sumTotalType(query); + return RestResult.ok(map); + } + + @ApiOperation(value = "9.统计问题分类", position = 9) + @GetMapping("/sumQuestionType") + public RestResult>> sumQuestionType(RepairTodoListQuery query) { + List> map = statisticService.sumQuestionType(query); + return RestResult.ok(map); + } + + @ApiOperation(value = "10.统计处理1到3次以上的成功次数", position = 10) + @GetMapping("/sumSuccess") + public RestResult>> sumSuccess(RepairTodoListQuery query) { + List> map = statisticService.sumSuccess(query); + return RestResult.ok(map); + } + + @ApiOperation(value = "11.统计每天报障数、响应速度、业务总数、故障率", position = 11) + @GetMapping("/sumEfficiencyDay") + @ApiOperationSupport( + responses = @DynamicResponseParameters(properties = { + @DynamicParameter(value = "date", name = "天 yyyy-MM-dd"), + @DynamicParameter(value = "reportTotal", name = "报障数"), + @DynamicParameter(value = "busTotal", name = "业务总数"), + @DynamicParameter(value = "faultRate", name = "故障率"), + @DynamicParameter(value = "resSpeed", name = "响应速度 小时单位,时间是工作时间8小时"), + }) + ) + public RestResult> sumEfficiency(RepairTodoListQuery query) { + Map list = statisticService.sumEfficiency(query); + return RestResult.ok(list); + } + + @ApiOperation(value = "12.统计前5个问题的分类", position = 12) + @GetMapping("/sumQuestionTopDay") + @ApiOperationSupport( + responses = @DynamicResponseParameters(properties = { + @DynamicParameter(value = "date", name = "天 yyyy-MM-dd"), + @DynamicParameter(value = "reportTotal", name = "报障数"), + }) + ) + public RestResult> sumQuestionTopDay(RepairTodoListQuery query) { + Map list = statisticService.sumQuestionTopDay(query); + return RestResult.ok(list); + } + + +} + diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/controller/SummaryController.java b/src/main/java/com/chinaweal/youfool/devops/repair/controller/SummaryController.java new file mode 100644 index 0000000..6496c65 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/controller/SummaryController.java @@ -0,0 +1,80 @@ +package com.chinaweal.youfool.devops.repair.controller; + + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.chinaweal.youfool.devops.repair.controller.query.RepairTodoListQuery; +import com.chinaweal.youfool.devops.repair.entity.RepairTodo; +import com.chinaweal.youfool.devops.repair.service.IRepairSummaryService; +import com.chinaweal.youfool.framework.springboot.rest.RestResult; +import com.chinaweal.youfool.framework.springboot.rest.ResultCode; +import com.github.xiaoymin.knife4j.annotations.ApiSort; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.time.LocalDate; +import java.time.LocalDateTime; + +/** + *

+ * 运维报障统计汇总 前端控制器 + *

+ * + * @author chinaweal + * @since 2020-08-13 + */ +@Api(tags = "6.运维报障统计汇总主动调用") +@ApiSort(6) +@Transactional("devopsTransactionManager") +@RestController +@RequestMapping("/repair/summary") +public class SummaryController { + + @Resource + private IRepairSummaryService iRepairSummaryService; + + @ApiOperation(value = "1.根据时间范围按天并区分机构汇总,相关报障数据信息", position = 1) + @GetMapping("/sumOrgDay") + @Transactional(value = "devopsTransactionManager", propagation = Propagation.NOT_SUPPORTED) + public RestResult sumAllOrgByDay(@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startTime, + @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endTime) { + + if (startTime.isAfter(endTime)) { + return RestResult.error(ResultCode.PARAM_IS_INVALID, "时间范围有误"); + } + + while (startTime.isBefore(endTime)) { + iRepairSummaryService.sumAllOrgByDay(startTime); + startTime = startTime.plusDays(1); + } + + return RestResult.ok(); + } + + @ApiOperation(value = "2.根据时间范围按天并区分机构和问题分类汇总,相关报障数据信息", position = 2) + @GetMapping("/sumOrgQDay") + @Transactional(value = "devopsTransactionManager", propagation = Propagation.NOT_SUPPORTED) + public RestResult sumAllOrgAndGroupQuestionByDay(@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startTime, + @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endTime) { + + if (startTime.isAfter(endTime)) { + return RestResult.error(ResultCode.PARAM_IS_INVALID, "时间范围有误"); + } + + while (startTime.isBefore(endTime)) { + iRepairSummaryService.sumAllOrgAndGroupQuestionByDay(startTime); + startTime = startTime.plusDays(1); + } + + return RestResult.ok(); + } + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/controller/query/RepairTodoListQuery.java b/src/main/java/com/chinaweal/youfool/devops/repair/controller/query/RepairTodoListQuery.java new file mode 100644 index 0000000..584c990 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/controller/query/RepairTodoListQuery.java @@ -0,0 +1,111 @@ +package com.chinaweal.youfool.devops.repair.controller.query; + +import com.chinaweal.youfool.devops.base.controller.query.BaseListQuery; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@ApiModel("运维报障列表参数") +@Data +public class RepairTodoListQuery extends BaseListQuery { + + @ApiModelProperty(value = "运维单ID 对应repair表,repair_id") + private String repairId; + @ApiModelProperty(value = "标题") + private String title; + @ApiModelProperty(value = "申报用户昵称") + private String nickname; + @ApiModelProperty(value = "申报用户userId") + private String userId; + @ApiModelProperty(value = "申报用户账号") + private String username; + @ApiModelProperty(value = "所属机构") + private String org; + @ApiModelProperty(value = "所属部门") + private String dept; + @ApiModelProperty(value = "所属业务处室id") + private String deptId; + @ApiModelProperty(value = "问题类型") + private String questionType; + @ApiModelProperty(value = "业务模块") + private String business; + @ApiModelProperty(value = "优先级别 1:紧急;2:高;3:中;4:低") + private Integer priority; + @ApiModelProperty(value = "报送时间开始") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime launchTimeStart; + @ApiModelProperty(value = "报送时间结束") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime launchTimeEnd; + @ApiModelProperty(value = "解决期限时间开始") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime solveLimitTimeStart; + @ApiModelProperty(value = "解决期限时间结束") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime solveLimitTimeEnd; + @ApiModelProperty(value = "环节步骤 多个可以用\",\"分割,declare:declare:已报障;assign:分派;handle:处理中;feedback:已处理;unresolved:未解决;resolved:已解决;end:结束;") + private String[] step; + @ApiModelProperty(value = "忽略的环节步骤 多个可以用\",\"分割,declare:declare:已报障;assign:分派;handle:处理中;feedback:已处理;unresolved:未解决;resolved:已解决;end:结束;") + private String[] notStep; + @ApiModelProperty(value = "运维工程师") + private String engineer; + @ApiModelProperty(value = "运维工程师username") + private String engineerUsername; + @ApiModelProperty(value = "处理更新时间开始") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime handleTimeStart; + @ApiModelProperty(value = "处理更新时间结束") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime handleTimeEnd; + @ApiModelProperty(value = "紧急程度 1:紧急;2:高;3:中;4:低") + private Integer urgency; + @ApiModelProperty(value = "自定义导出表头列表") + private String[] fields; + @ApiModelProperty(value = "根据待办ID导出") + private String[] todoIds; + @ApiModelProperty(value = "催单,不为空则只查询催单记录") + private Integer reminder; + @ApiModelProperty(value = "根据催单排序优先") + private Boolean isReminderSort; + @ApiModelProperty(value = "业务受理号") + private String busAcceptNo; + @ApiModelProperty(value = "业务要求办理时效") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime busHandleTime; + @ApiModelProperty(value = "业务办理分类") + private String busClassify; + @ApiModelProperty(value = "业务办理业务环节") + private String busStep; + @ApiModelProperty(value = "多个所属部门精准搜索") + private List orgList; + @ApiModelProperty(value = "多个所属部门模糊") + private List orgListLike; + @ApiModelProperty(value = "多个部门id") + private List orgIdList; + @ApiModelProperty(value = "负责人账号") + private String leaderUsername; + @ApiModelProperty(value = "负责人昵称") + private String leaderNickname; + @ApiModelProperty(value = "故障内容") + private String faultDescription; + @ApiModelProperty(value = "最后处理反馈时间开始") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime feedbackTimeStart; + @ApiModelProperty(value = "最后处理反馈时间结束") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime feedbackTimeEnd; + @ApiModelProperty(value = "标签") + private List labels; + @ApiModelProperty(value = "查询的页面tab标识") + private String tabId; + @ApiModelProperty(value = "分派人员名称") + private String assignPersonnel; + @ApiModelProperty(value = "工单来源") + private List source; +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/entity/Notification.java b/src/main/java/com/chinaweal/youfool/devops/repair/entity/Notification.java new file mode 100644 index 0000000..15688da --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/entity/Notification.java @@ -0,0 +1,149 @@ +package com.chinaweal.youfool.devops.repair.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.chinaweal.youfool.framework.springboot.json.LocalDateTimeStringSerializer; +import com.chinaweal.youfool.framework.springboot.mybatis.plus.SuperEntity; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.math.BigDecimal; +import java.time.LocalDate; + +/** + *

+ * 通报 + *

+ * + * @author chinaweal + * @since 2020-11-02 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +@TableName("NOTIFICATION") +@ApiModel(value = "Notification对象", description = "通报") +public class Notification extends SuperEntity { + + private static final long serialVersionUID = 1L; + + /** + * id + */ + @ApiModelProperty(value = "id") + @TableId(value = "UUID", type = IdType.ASSIGN_UUID) + private String uuid; + + /** + * 统计月份 + */ + @ApiModelProperty(value = "统计月份") + @TableField("MONTH_DATE") + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDate monthDate; + + /** + * 统计单位 + */ + @ApiModelProperty(value = "统计单位") + @TableField("ORG") + private String org; + + /** + * 报障总数 + */ + @ApiModelProperty(value = "报障总数") + @TableField("TOTAL") + private BigDecimal total; + + /** + * 已解决 + */ + @ApiModelProperty(value = "已解决") + @TableField("RESOLVED") + private BigDecimal resolved; + + /** + * 待确认 + */ + @ApiModelProperty(value = "待确认") + @TableField("CONFIRMED") + private BigDecimal confirmed; + + /** + * 未处理 + */ + @ApiModelProperty(value = "未处理") + @TableField("UNTREATED") + private BigDecimal untreated; + + /** + * 历史报障总数 + */ + @ApiModelProperty(value = "历史报障总数") + @TableField("HISTORY_TOTAL") + private BigDecimal historyTotal; + + /** + * 历史已解决 + */ + @ApiModelProperty(value = "历史已解决") + @TableField("HISTORY_RESOLVED") + private BigDecimal historyResolved; + + /** + * 历史待确认 + */ + @ApiModelProperty(value = "历史待确认") + @TableField("HISTORY_CONFIRMED") + private BigDecimal historyConfirmed; + + /** + * 历史未处理 + */ + @ApiModelProperty(value = "历史未处理") + @TableField("HISTORY_UNTREATED") + private BigDecimal historyUntreated; + + /** + * 一次处理 + */ + @ApiModelProperty(value = "一次处理") + @TableField("ONE") + private BigDecimal one; + + /** + * 两次处理 + */ + @ApiModelProperty(value = "两次处理") + @TableField("TWO") + private BigDecimal two; + + /** + * 三次处理以上 + */ + @ApiModelProperty(value = "三次处理以上") + @TableField("THREE") + private BigDecimal three; + + /** + * 故障平均处理时长 单位秒 + */ + @ApiModelProperty(value = "故障平均处理时长 单位秒") + @TableField("AVG_HANDLE") + private BigDecimal avgHandle; + + /** + * 故障平均解决时长 单位秒 + */ + @ApiModelProperty(value = "故障平均解决时长 单位秒") + @TableField("AVG_RESOLVED") + private BigDecimal avgResolved; + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/entity/Repair.java b/src/main/java/com/chinaweal/youfool/devops/repair/entity/Repair.java new file mode 100644 index 0000000..f190522 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/entity/Repair.java @@ -0,0 +1,286 @@ +package com.chinaweal.youfool.devops.repair.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.chinaweal.youfool.framework.springboot.json.LocalDateTimeStringSerializer; +import com.chinaweal.youfool.framework.springboot.mybatis.plus.SuperEntity; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; +import java.util.List; + +/** + *

+ * 运维报障信息 + *

+ * + * @author chinaweal + * @since 2020-06-05 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +@TableName("REPAIR") +@ApiModel(value = "Repair对象", description = "运维报障信息") +public class Repair extends SuperEntity { + + private static final long serialVersionUID = 1L; + + /** + * 运维单ID + */ + @ApiModelProperty(value = "运维单ID") + @TableId("REPAIR_ID") + private String repairId; + + /** + * 标题 + */ + @ApiModelProperty(value = "标题") + @TableField("TITLE") + private String title; + + /** + * 申报账号ID + */ + @ApiModelProperty(value = "申报账号ID") + @TableField("USER_ID") + private String userId; + + /** + * 申报用户昵称 + */ + @ApiModelProperty(value = "申报用户昵称") + @TableField("NICKNAME") + private String nickname; + + /** + * 申报用户账号 + */ + @ApiModelProperty(value = "申报用户账号") + @TableField("USERNAME") + private String username; + + /** + * 所属机构 + */ + @ApiModelProperty(value = "所属机构") + @TableField("ORG") + private String org; + + /** + * 所属机构Id + */ + @ApiModelProperty(value = "所属机构Id") + @TableField("ORG_ID") + private String orgId; + + /** + * 所属部门 + */ + @ApiModelProperty(value = "所属部门") + @TableField("DEPT") + private String dept; + + /** + * 所属部门Id + */ + @ApiModelProperty(value = "所属部门Id") + @TableField("DEPT_ID") + private String deptId; + + /** + * 联系电话 + */ + @ApiModelProperty(value = "联系电话") + @TableField("PHONE") + private String phone; + + /** + * 问题类型 + */ + @ApiModelProperty(value = "问题类型") + @TableField("QUESTION_TYPE") + private String questionType; + + /** + * 业务模块 + */ + @ApiModelProperty(value = "业务模块") + @TableField("BUSINESS") + private String business; + + /** + * 优先级别 1:紧急;2:高;3:中;4:低 + */ + @ApiModelProperty(value = "优先级别 1:紧急;2:高;3:中;4:低") + @TableField("PRIORITY") + private Integer priority; + + /** + * 紧急程度 1:紧急;2:高;3:中;4:低 + */ + @ApiModelProperty(value = "紧急程度 1:紧急;2:高;3:中;4:低") + @TableField("URGENCY") + private Integer urgency; + + /** + * 故障描述 + */ + @ApiModelProperty(value = "故障描述") + @TableField("FAULT_DESCRIPTION") + private String faultDescription; + + /** + * 报送时间 + */ + @ApiModelProperty(value = "报送时间") + @TableField("LAUNCH_TIME") + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime launchTime; + + /** + * 解决期限时间 + */ + @ApiModelProperty(value = "解决期限时间") + @TableField("SOLVE_LIMIT_TIME") + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime solveLimitTime; + + /** + * 当前环节信息 + */ + @ApiModelProperty(value = "当前环节处理信息") + @TableField(exist = false) + private RepairHandle currentHandle; + + /** + * 运维报障处理流程记录 + */ + @ApiModelProperty(value = "运维报障处理流程记录列表") + @TableField(exist = false) + private List repairHandles; + + /** + * 问题相关文件列表 + */ + @ApiModelProperty(value = "问题相关附件") + @TableField(exist = false) + private List questionFiles; + + /** + * 问题相关文件列表 + */ + @ApiModelProperty(value = "解答相关附件") + @TableField(exist = false) + private List answerFiles; + + /** + * 业务受理号 + */ + @ApiModelProperty(value = "业务受理号") + @TableField("BUS_ACCEPT_NO") + private String busAcceptNo; + + /** + * 业务办理分类标签 + */ + @ApiModelProperty(value = "业务办理分类") + @TableField("BUS_CLASSIFY") + private String busClassify; + + /** + * 业务办理业务环节 + */ + @ApiModelProperty(value = "业务办理业务环节") + @TableField("BUS_STEP") + private String busStep; + + /** + * 业务要求办理时效 + */ + @ApiModelProperty(value = "业务要求办理时效") + @TableField("BUS_HANDLE_TIME") + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime busHandleTime; + + /** + * 计划完成时间 + */ + @ApiModelProperty(value = "计划完成时间") + @TableField("PLANNED_TIME") + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime plannedTime; + + /** + * 实际完成时间 + */ + @ApiModelProperty(value = "实际完成时间") + @TableField("REALITY_TIME") + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime realityTime; + + /** + * 负责人昵称 + */ + @ApiModelProperty(value = "负责人昵称") + @TableField("LEADER_NICKNAME") + private String leaderNickname; + + /** + * 负责人账号 + */ + @ApiModelProperty(value = "负责人账号") + @TableField("LEADER_USERNAME") + private String leaderUsername; + + @ApiModelProperty(value = "待办信息") + @TableField(exist = false) + private RepairTodo repairTodo; + + @ApiModelProperty(value = "标签") + @TableField(exist = false) + private List labels; + + /** + * 解决思路填录 + */ + @ApiModelProperty(value = "解决思路填录") + @TableField("THINKING") + private String thinking; + + /** + * 标签字符 + */ + @ApiModelProperty(value = "标签字符") + @TableField("LABEL") + private String label; + + /** + * 业务企业名称 + */ + @ApiModelProperty(value = "业务企业名称") + @TableField("BUS_ENT_NAME") + private String busEntName; + + /** + * 是否需要导出数据(0否1是) + */ + @ApiModelProperty("是否需要导出数据(0否1是)") + @TableField("NEED_DATA_EXPORT") + private String needDataExport; + + /** + * 报障单来源 + * 1:内网、2:特设系统外网 + */ + @ApiModelProperty("报障单来源") + @TableField(exist = false) + private String source; +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/entity/RepairFile.java b/src/main/java/com/chinaweal/youfool/devops/repair/entity/RepairFile.java new file mode 100644 index 0000000..2cfb0c2 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/entity/RepairFile.java @@ -0,0 +1,97 @@ +package com.chinaweal.youfool.devops.repair.entity; + +import com.baomidou.mybatisplus.annotation.*; +import com.chinaweal.youfool.framework.springboot.json.LocalDateTimeStringSerializer; +import com.chinaweal.youfool.framework.springboot.mybatis.plus.SuperEntity; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; + +/** + *

+ * 运维报障附件 + *

+ * + * @author chinaweal + * @since 2020-06-05 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +@TableName("REPAIR_FILE") +@ApiModel(value = "RepairFile对象", description = "运维报障附件") +public class RepairFile extends SuperEntity { + + private static final long serialVersionUID = 1L; + + /** + * 文件ID + */ + @ApiModelProperty(value = "文件ID") + @TableId(value = "UUID", type = IdType.ASSIGN_UUID) + private String uuid; + + /** + * 文件名 + */ + @ApiModelProperty(value = "文件名") + @TableField("FILE_NAME") + private String fileName; + + /** + * 文件类型 + */ + @ApiModelProperty(value = "文件类型") + @TableField("FILE_TYPE") + private String fileType; + + /** + * 类型 question:问题相关附件;answer:解答相关附件 + */ + @ApiModelProperty(value = "类型 question:问题相关附件;answer:解答相关附件") + @TableField("TYPE") + private String type; + + /** + * 文件路径 + */ + @ApiModelProperty(value = "文件路径") + @TableField("FILE_PATH") + private String filePath; + + /** + * 文件大小 单位字节 + */ + @ApiModelProperty(value = "文件大小 单位字节") + @TableField("FILE_SIZE") + private Long fileSize; + + /** + * 运维单ID 对应repair表的,repair_id + */ + @ApiModelProperty(value = "运维单ID 对应repair表的,repair_id") + @TableField("REPAIR_ID") + private String repairId; + + /** + * 处理ID 对应运维报障处理流程记录 + */ + @ApiModelProperty(value = "处理ID 对应运维报障处理流程记录") + @TableField("HANDLE_ID") + private String handleId; + + + /** + * 上传时间 + */ + @ApiModelProperty(value = "上传时间") + @TableField(value = "UPLOAD_TIME") + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime uploadTime; + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/entity/RepairHandle.java b/src/main/java/com/chinaweal/youfool/devops/repair/entity/RepairHandle.java new file mode 100644 index 0000000..e35ce3b --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/entity/RepairHandle.java @@ -0,0 +1,189 @@ +package com.chinaweal.youfool.devops.repair.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.chinaweal.youfool.framework.springboot.json.LocalDateTimeStringSerializer; +import com.chinaweal.youfool.framework.springboot.mybatis.plus.SuperEntity; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; +import java.util.List; + +/** + *

+ * 运维报障处理流程记录 + *

+ * + * @author chinaweal + * @since 2020-06-05 + */ +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +@TableName("REPAIR_HANDLE") +@ApiModel(value = "RepairHandle对象", description = "运维报障处理流程记录") +public class RepairHandle extends SuperEntity { + + private static final long serialVersionUID = 1L; + + /** + * 处理ID + */ + @ApiModelProperty(value = "处理ID") + @TableId(value = "HANDLE_ID", type = IdType.ASSIGN_UUID) + private String handleId; + + /** + * 报障待办ID 对应repair_todo表的,todo_id + */ + @ApiModelProperty(value = "报障待办ID 对应repair_todo表的,todo_id") + @TableField("TODO_ID") + private String todoId; + + /** + * 运维单ID 对应repair表的,repair_id + */ + @ApiModelProperty(value = "运维单ID 对应repair表的,repair_id") + @TableField("REPAIR_ID") + private String repairId; + + /** + * 处理人 + */ + @ApiModelProperty(value = "处理人") + @TableField("HANDLE_NICKNAME") + private String handleNickname; + + /** + * 处理人账号 + */ + @ApiModelProperty(value = "处理人账号") + @TableField("HANDLE_USERNAME") + private String handleUsername; + + /** + * 环节步骤 declare:declare:已报障;assign:分派;handle:处理中;feedback:已处理;unresolved:未解决;resolved:已解决;end:结束; + */ + @ApiModelProperty(value = "环节步骤 declare:declare:已报障;assign:分派;handle:处理中;feedback:已处理;unresolved:未解决;resolved:已解决;end:结束;") + @TableField("STEP") + private String step; + + /** + * 生成时间 + */ + @ApiModelProperty(value = "生成时间") + @TableField("HAPPEN_TIME") + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime happenTime; + + /** + * 处理结果 + */ + @ApiModelProperty(value = "处理结果") + @TableField("RESULT") + private String result; + + /** + * 优先级别 1:紧急;2:高;3:中;4:低 + */ + @ApiModelProperty(value = "优先级别 1:紧急;2:高;3:中;4:低") + @TableField(exist = false) + private Integer priority; + + /** + * 问题分类 + */ + @ApiModelProperty(value = "问题分类") + @TableField(exist = false) + private String questionType; + + /** + * 问题分类 + */ + @ApiModelProperty(value = "问题标签") + @TableField(exist = false) + private String[] labels; + + /** + * 环节状态 0:过期;1:有效 + */ + @ApiModelProperty(value = "环节状态 0:过期;1:有效") + @TableField("STATUS") + private String status; + + /** + * 下一个处理人 + */ + @ApiModelProperty(value = "下一个处理人") + @TableField(exist = false) + private String nextHandleNickname; + + /** + * 下一个处理人username + */ + @ApiModelProperty(value = "下一个处理人username") + @TableField(exist = false) + private String nextHandleUsername; + + @TableField(exist = false) + @ApiModelProperty(value = "附件列表") + private List files; + + @TableField(exist = false) + @ApiModelProperty(value = "计划完成时间") + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime plannedTime; + + /** + * 负责人昵称 + */ + @ApiModelProperty(value = "负责人昵称") + @TableField(exist = false) + private String leaderNickname; + + /** + * 解决思路填录 + */ + @ApiModelProperty(value = "解决思路填录") + @TableField(exist = false) + private String thinking; + + /** + * 负责人账号 + */ + @ApiModelProperty(value = "负责人账号") + @TableField(exist = false) + private String leaderUsername; + + public LocalDateTime getHappenTime() { + return happenTime; + } + + public void setHappenTime(LocalDateTime happenTime) { + this.happenTime = happenTime; + } + + public RepairHandle(String todoId, String repairId, String step) { + this.todoId = todoId; + this.repairId = repairId; + this.step = step; + } + + public RepairHandle(String todoId, String repairId, String step, String handleUsername, String handleNickname, String result) { + this.todoId = todoId; + this.repairId = repairId; + this.step = step; + this.handleUsername = handleUsername; + this.handleNickname = handleNickname; + this.result = result; + } +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/entity/RepairLabel.java b/src/main/java/com/chinaweal/youfool/devops/repair/entity/RepairLabel.java new file mode 100644 index 0000000..070f2e9 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/entity/RepairLabel.java @@ -0,0 +1,55 @@ +package com.chinaweal.youfool.devops.repair.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableField; +import com.chinaweal.youfool.framework.springboot.mybatis.plus.SuperEntity; +import com.chinaweal.youfool.framework.springboot.json.LocalDateTimeStringSerializer; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + *

+ * 运维单标签 + *

+ * + * @author chinaweal + * @since 2020-07-10 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +@TableName("REPAIR_LABEL") +@ApiModel(value = "Label对象", description = "运维单标签") +public class RepairLabel extends SuperEntity { + + private static final long serialVersionUID = 1L; + + /** + * 标签ID + */ + @ApiModelProperty(value = "标签ID") + @TableId(value = "LABEL_ID", type = IdType.ASSIGN_UUID) + private String labelId; + + /** + * 名称 + */ + @ApiModelProperty(value = "名称") + @TableField("NAME") + private String name; + + /** + * 运维单ID 对应repair表,repair_id + */ + @ApiModelProperty(value = "运维单ID 对应repair表,repair_id") + @TableField("REPAIR_ID") + private String repairId; + + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/entity/RepairSummary.java b/src/main/java/com/chinaweal/youfool/devops/repair/entity/RepairSummary.java new file mode 100644 index 0000000..a5f01dc --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/entity/RepairSummary.java @@ -0,0 +1,95 @@ +package com.chinaweal.youfool.devops.repair.entity; + +import java.math.BigDecimal; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.time.LocalDateTime; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.chinaweal.youfool.framework.springboot.mybatis.plus.SuperEntity; +import com.chinaweal.youfool.framework.springboot.json.LocalDateTimeStringSerializer; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + *

+ * 运维报障统计汇总 + *

+ * + * @author chinaweal + * @since 2020-08-13 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +@TableName("REPAIR_SUMMARY") +@ApiModel(value = "Summary对象", description = "运维报障统计汇总") +public class RepairSummary extends SuperEntity { + + private static final long serialVersionUID = 1L; + + /** + * id + */ + @ApiModelProperty(value = "id") + @TableId(value = "UUID", type = IdType.ASSIGN_UUID) + private String uuid; + + /** + * 时间 + */ + @ApiModelProperty(value = "时间") + @TableField("TIME") + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime time; + + /** + * 统计类型 多种统计汇总结果类型,然后所有表字段拉平存放 + */ + @ApiModelProperty(value = "统计类型 多种统计汇总结果类型,然后所有表字段拉平存放") + @TableField("TYPE") + private String type; + + /** + * 问题分类 + */ + @ApiModelProperty(value = "问题分类") + @TableField("QUESTION_TYPE") + private String questionType; + + /** + * 业务总数 + */ + @ApiModelProperty(value = "业务总数") + @TableField("BUS_TOTAL") + private BigDecimal busTotal; + + /** + * 报障数 + */ + @ApiModelProperty(value = "报障数") + @TableField("REPORT_TOTAL") + private BigDecimal reportTotal; + + /** + * 处理数 + */ + @ApiModelProperty(value = "处理数") + @TableField("HANDLE_TOTAL") + private BigDecimal handleTotal; + + /** + * 机构 + */ + @ApiModelProperty(value = "机构") + @TableField("ORG") + private String org; + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/entity/RepairTodo.java b/src/main/java/com/chinaweal/youfool/devops/repair/entity/RepairTodo.java new file mode 100644 index 0000000..14e1dde --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/entity/RepairTodo.java @@ -0,0 +1,337 @@ +package com.chinaweal.youfool.devops.repair.entity; + +import com.baomidou.mybatisplus.annotation.*; +import com.chinaweal.youfool.framework.springboot.json.LocalDateTimeStringSerializer; +import com.chinaweal.youfool.framework.springboot.mybatis.plus.SuperEntity; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +/** + *

+ * 运维报障待办 + *

+ * + * @author chinaweal + * @since 2020-06-05 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +@TableName(schema = "DEVOPS", value = "REPAIR_TODO") +@ApiModel(value = "RepairTodo对象", description = "运维报障待办") +@JsonIgnoreProperties(value = {"handler"}) +public class RepairTodo extends SuperEntity { + + private static final long serialVersionUID = 1L; + + /** + * 报障待办ID + */ + @ApiModelProperty(value = "报障待办ID") + @TableId(value = "TODO_ID", type = IdType.ASSIGN_UUID) + private String todoId; + + /** + * 运维单ID 对应repair表,repair_id + */ + @ApiModelProperty(value = "运维单ID 对应repair表,repair_id") + @TableField("REPAIR_ID") + private String repairId; + + /** + * 标题 + */ + @ApiModelProperty(value = "标题") + @TableField("TITLE") + private String title; + + /** + * 申报账号ID + */ + @ApiModelProperty(value = "申报账号ID") + @TableField("USER_ID") + private String userId; + + /** + * 申报用户昵称 + */ + @ApiModelProperty(value = "申报用户昵称") + @TableField("NICKNAME") + private String nickname; + + /** + * 申报用户账号 + */ + @ApiModelProperty(value = "申报用户账号") + @TableField("USERNAME") + private String username; + + /** + * 所属机构 + */ + @ApiModelProperty(value = "所属机构") + @TableField("ORG") + private String org; + + /** + * 所属机构Id + */ + @ApiModelProperty(value = "所属机构Id") + @TableField("ORG_ID") + private String orgId; + + /** + * 所属部门 + */ + @ApiModelProperty(value = "所属部门") + @TableField("DEPT") + private String dept; + + /** + * 所属部门Id + */ + @ApiModelProperty(value = "所属部门Id") + @TableField("DEPT_ID") + private String deptId; + + /** + * 问题分类 + */ + @ApiModelProperty(value = "问题分类") + @TableField(exist = false) + private String questionType; + + /** + * 标签 + */ + @ApiModelProperty(value = "标签") + @TableField(exist = false) + private List labels; + + /** + * 业务模块 + */ + @ApiModelProperty(value = "业务模块") + @TableField("BUSINESS") + private String business; + + /** + * 优先级别 1:紧急;2:高;3:中;4:低 + */ + @ApiModelProperty(value = "优先级别 1:紧急;2:高;3:中;4:低") + @TableField("PRIORITY") + private Integer priority; + + /** + * 紧急程度 1:紧急;2:高;3:中;4:低 + */ + @ApiModelProperty(value = "紧急程度 1:紧急;2:高;3:中;4:低") + @TableField("URGENCY") + private Integer urgency; + + /** + * 报送时间 + */ + @ApiModelProperty(value = "报送时间") + @TableField("LAUNCH_TIME") + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime launchTime; + + /** + * 解决期限时间 + */ + @ApiModelProperty(value = "解决期限时间") + @TableField("SOLVE_LIMIT_TIME") + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime solveLimitTime; + + /** + * 环节步骤 declare:declare:已报障;assign:分派;handle:处理中;feedback:已处理;unresolved:未解决;resolved:已解决;end:结束; + */ + @ApiModelProperty(value = "环节步骤 declare:declare:已报障;assign:分派;handle:处理中;feedback:已处理;unresolved:未解决;resolved:已解决;end:结束;") + @TableField("STEP") + private String step; + + /** + * 运维工程师 + */ + @ApiModelProperty(value = "运维工程师") + @TableField("ENGINEER") + private String engineer; + + /** + * 运维工程师username + */ + @ApiModelProperty(value = "运维工程师username") + @TableField("ENGINEER_USERNAME") + private String engineerUsername; + + /** + * 催单次数 + */ + @ApiModelProperty(value = "催单次数") + @TableField("REMINDER") + private Integer reminder; + + /** + * 处理更新时间 + */ + @ApiModelProperty(value = "处理更新时间") + @TableField("HANDLE_TIME") + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime handleTime; + + /** + * 是否删除 0:有效;1:删除 + */ + @ApiModelProperty(value = "是否删除 0:有效;1:删除") + @TableLogic(value = "0", delval = "1") + @TableField("DELETED") + private String deleted; + + /** + * 故障描述 + */ + @ApiModelProperty(value = "故障描述") + @TableField(exist = false) + private String faultDescription; + /** + * 业务受理号 + */ + @ApiModelProperty(value = "业务受理号") + @TableField(exist = false) + private String busAcceptNo; + + /** + * 业务要求办理时效 + */ + @ApiModelProperty(value = "业务要求办理时效") + @TableField(exist = false) + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime busHandleTime; + + /** + * 业务办理分类标签 + */ + @ApiModelProperty(value = "业务办理分类标签") + @TableField(exist = false) + private String busClassify; + /** + * 业务办理业务环节 + */ + @ApiModelProperty(value = "业务办理业务环节") + @TableField(exist = false) + private String busStep; + + /** + * 计划完成时间 + */ + @ApiModelProperty(value = "计划完成时间") + @TableField(exist = false) + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime plannedTime; + + /** + * 实际完成时间 + */ + @ApiModelProperty(value = "实际完成时间") + @TableField(exist = false) + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime realityTime; + /** + * 负责人昵称 + */ + @ApiModelProperty(value = "负责人昵称") + @TableField(exist = false) + private String leaderNickname; + + /** + * 负责人账号 + */ + @ApiModelProperty(value = "负责人账号") + @TableField(exist = false) + private String leaderUsername; + + @ApiModelProperty(value = "解决时长,单位小时") + @TableField(exist = false) + private BigDecimal solveTime; + + /** + * 最后处理反馈时间 + */ + @ApiModelProperty(value = "最后处理反馈时间") + @TableField("FEEDBACK_TIME") + @JsonSerialize(using = LocalDateTimeStringSerializer.class) + private LocalDateTime feedbackTime; + + @ApiModelProperty(value = "最后处理反馈时长") + @TableField(exist = false) + private BigDecimal feedbackTimeSize; + + @ApiModelProperty(value = "解决思路填录") + @TableField(exist = false) + private String thinking; + + /** + * 标签集合字符 + */ + @ApiModelProperty(value = "标签集合字符','分割") + @TableField(exist = false) + private String label; + + /** + * 是否需要导出数据(0否1是) + */ + @ApiModelProperty("是否需要导出数据(0否1是)") + @TableField(exist = false) + private String needDataExport; + + /** + * 报障单来源 + * 1:内网、2:特设系统外网、3:佛山pc年报 + */ + @ApiModelProperty("报障单来源") + @TableField("SOURCE") + private String source; + + public LocalDateTime getLaunchTime() { + return launchTime; + } + + public void setLaunchTime(LocalDateTime launchTime) { + this.launchTime = launchTime; + } + + public LocalDateTime getSolveLimitTime() { + return solveLimitTime; + } + + public void setSolveLimitTime(LocalDateTime solveLimitTime) { + this.solveLimitTime = solveLimitTime; + } + + public LocalDateTime getHandleTime() { + return handleTime; + } + + public void setHandleTime(LocalDateTime handleTime) { + this.handleTime = handleTime; + } + + public LocalDateTime getBusHandleTime() { + return busHandleTime; + } + + public void setBusHandleTime(LocalDateTime busHandleTime) { + this.busHandleTime = busHandleTime; + } +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/excel/CustomRowCellWriteHandler.java b/src/main/java/com/chinaweal/youfool/devops/repair/excel/CustomRowCellWriteHandler.java new file mode 100644 index 0000000..9e4ffad --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/excel/CustomRowCellWriteHandler.java @@ -0,0 +1,142 @@ +package com.chinaweal.youfool.devops.repair.excel; + +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.write.handler.CellWriteHandler; +import com.alibaba.excel.write.handler.RowWriteHandler; +import com.alibaba.excel.write.handler.SheetWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteTableHolder; +import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddress; + +import java.util.List; + +/** + * 自定义表格样式 + */ +public class CustomRowCellWriteHandler implements CellWriteHandler, RowWriteHandler, SheetWriteHandler { + + private Workbook workbook; + private CellStyle defaultCellStyle; + + /** + * 设置居中和边框 + * + * @return + */ + private CellStyle getBorderAndCenter(CellStyle style) { + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setBorderBottom(BorderStyle.THIN); + style.setBorderLeft(BorderStyle.THIN); + style.setBorderTop(BorderStyle.THIN); + style.setBorderRight(BorderStyle.THIN); + return style; + } + + @Override + public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) { + + } + + @Override + public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { + + } + + @Override + public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { + + } + + @Override + public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, + List cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { + Integer columnIndex = head.getColumnIndex(); + if (!isHead) { + //内容 + cell.setCellStyle(defaultCellStyle); + } else if (relativeRowIndex == 0 && columnIndex == 0) { + //大标题 + CellStyle cellStyle = workbook.createCellStyle(); + Font font = workbook.createFont(); + font.setFontName("宋体"); + font.setFontHeightInPoints((short) 14); + font.setBold(true); + cellStyle.setFont(font); + cell.setCellStyle(getBorderAndCenter(cellStyle)); + } else if (relativeRowIndex == 1) { + //小表头 + CellStyle cellStyle = workbook.createCellStyle(); + Font font = workbook.createFont(); + font.setFontName("宋体"); + font.setFontHeightInPoints((short) 12); + font.setBold(true); + cellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.index); + cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); + cellStyle.setFont(font); + cell.setCellStyle(getBorderAndCenter(cellStyle)); + } + } + + @Override + public void beforeRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Integer rowIndex, Integer relativeRowIndex, Boolean isHead) { + + } + + @Override + public void afterRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) { + + } + + @Override + public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) { + if (!isHead) { + //默认高度 + row.setHeightInPoints(20); + } else if (relativeRowIndex == 0) { + List> heads = writeSheetHolder.getHead(); + Sheet sheet = writeSheetHolder.getSheet(); + //大表头 + int size = heads.size(); + //合并标题内容 + CellRangeAddress hTitleRegion = new CellRangeAddress(0, 0, 0, size - 1); + sheet.addMergedRegion(hTitleRegion); + row.setHeightInPoints(40); + } else if (relativeRowIndex == 1) { + List> heads = writeSheetHolder.getHead(); + Sheet sheet = writeSheetHolder.getSheet(); + int size = heads.size(); + row.setHeightInPoints(25); + //添加小表头筛选 + CellRangeAddress cellRangeAddress = new CellRangeAddress(1, 1, 0, size - 1); + sheet.setAutoFilter(cellRangeAddress); + //判断列宽 + sheet.setColumnWidth(0, 2000); + for (int i = 1; i < size; i++) { + sheet.setColumnWidth(i, 5000); + } + } + } + + void init(WriteWorkbookHolder writeWorkbookHolder) { + this.workbook = writeWorkbookHolder.getWorkbook(); + CellStyle cellStyle = workbook.createCellStyle(); + Font font = workbook.createFont(); + font.setFontName("宋体"); + font.setFontHeightInPoints((short) 12); + cellStyle.setFont(font); + this.defaultCellStyle = getBorderAndCenter(cellStyle); + } + + @Override + public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { + } + + @Override + public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { + init(writeWorkbookHolder); + } +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/excel/LocalDateTimeConverter.java b/src/main/java/com/chinaweal/youfool/devops/repair/excel/LocalDateTimeConverter.java new file mode 100644 index 0000000..5304d71 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/excel/LocalDateTimeConverter.java @@ -0,0 +1,41 @@ +package com.chinaweal.youfool.devops.repair.excel; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +/** + * @author itluc + */ +public class LocalDateTimeConverter implements Converter { + @Override + public Class supportJavaTypeKey() { + return LocalDateTime.class; + + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + @Override + public LocalDateTime convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null) { + return LocalDateTime.parse(cellData.getStringValue()); + } else { + return LocalDateTime.parse(cellData.getStringValue(), DateTimeFormatter.ofPattern(contentProperty.getDateTimeFormatProperty().getFormat())); + } + } + + @Override + public CellData convertToExcelData(LocalDateTime value, ExcelContentProperty + contentProperty, GlobalConfiguration globalConfiguration) { + return new CellData(value.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); + } +} \ No newline at end of file diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/excel/RepairTodoExcel.java b/src/main/java/com/chinaweal/youfool/devops/repair/excel/RepairTodoExcel.java new file mode 100644 index 0000000..d34dba0 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/excel/RepairTodoExcel.java @@ -0,0 +1,147 @@ +package com.chinaweal.youfool.devops.repair.excel; + + +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +import static com.chinaweal.youfool.devops.repair.service.IRepairHandleService.*; + +@Data +public class RepairTodoExcel { + + private Integer no; + private String repairId; + private String title; + private String nickname; + private String username; + private String org; + private String dept; + private String business; + private String priority; + private String urgency; + private LocalDateTime solveLimitTime; + private String step; + private String engineer; + private LocalDateTime handleTime; + private String faultDescription; + private LocalDateTime launchTime; + private String reminder; + private String busAcceptNo; + private LocalDateTime busHandleTime; + private LocalDateTime plannedTime; + private LocalDateTime realityTime; + private LocalDateTime feedbackTime; + private String questionType; + private String label; + private String leaderNickname; + private String solveTime; + private String feedbackTimeSize; + private String busStep; + private String busClassify; + + public void setPriority(Integer priority) { + if (priority == null) return; + switch (priority) { + case 1: { + this.priority = "紧急"; + break; + } + case 2: { + this.priority = "高"; + break; + } + case 3: { + this.priority = "中"; + break; + } + case 4: { + this.priority = "低"; + break; + } + default: + break; + } + } + + public void setUrgency(Integer urgency) { + if (urgency == null) return; + switch (urgency) { + case 1: { + this.urgency = "紧急"; + break; + } + case 2: { + this.urgency = "高"; + break; + } + case 3: { + this.urgency = "中"; + break; + } + case 4: { + this.urgency = "低"; + break; + } + default: + break; + } + } + + public void setStep(String step) { + if (step == null) return; + switch (step) { + case DECLARE: { + this.step = "已报障"; + break; + } + case ASSIGN: { + this.step = "分派"; + break; + } + case HANDLE: { + this.step = "处理中"; + break; + } + case FEEDBACK: { + this.step = "已处理"; + break; + } + case UNRESOLVED: { + this.step = "未解决"; + break; + } + case RESOLVED: { + this.step = "已解决"; + break; + } + case END: { + this.step = "结束"; + break; + } + default: + break; + } + } + + public void setReminder(Integer reminder) { + if (reminder != null) { + this.reminder = "催单"; + } + } + + public void setSolveTime(BigDecimal solveTime) { + if (solveTime != null) { + this.solveTime = solveTime.setScale(3, BigDecimal.ROUND_HALF_UP) + " 小时"; + } + } + + public void setFeedbackTimeSize(BigDecimal feedbackTimeSize) { + if (feedbackTimeSize != null) { + this.feedbackTimeSize = feedbackTimeSize.setScale(3, BigDecimal.ROUND_HALF_UP) + " 小时"; + } + } +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/mapper/NotificationMapper.java b/src/main/java/com/chinaweal/youfool/devops/repair/mapper/NotificationMapper.java new file mode 100644 index 0000000..0a3cb1b --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/mapper/NotificationMapper.java @@ -0,0 +1,23 @@ +package com.chinaweal.youfool.devops.repair.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.chinaweal.youfool.devops.repair.entity.Notification; +import org.apache.ibatis.annotations.Param; + +import java.time.LocalDate; +import java.util.List; +import java.util.Map; + +/** + *

+ * 通报 Mapper 接口 + *

+ * + * @author chinaweal + * @since 2020-11-02 + */ +public interface NotificationMapper extends BaseMapper { + List> dailyHandledUserNum(@Param("start") LocalDate start, @Param("end") LocalDate end); + + List> unhandledUserNum(); +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/mapper/RepairFileMapper.java b/src/main/java/com/chinaweal/youfool/devops/repair/mapper/RepairFileMapper.java new file mode 100644 index 0000000..f7aa07d --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/mapper/RepairFileMapper.java @@ -0,0 +1,16 @@ +package com.chinaweal.youfool.devops.repair.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.chinaweal.youfool.devops.repair.entity.RepairFile; + +/** + *

+ * 运维报障附件 Mapper 接口 + *

+ * + * @author chinaweal + * @since 2020-06-05 + */ +public interface RepairFileMapper extends BaseMapper { + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/mapper/RepairHandleMapper.java b/src/main/java/com/chinaweal/youfool/devops/repair/mapper/RepairHandleMapper.java new file mode 100644 index 0000000..f11eefa --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/mapper/RepairHandleMapper.java @@ -0,0 +1,53 @@ +package com.chinaweal.youfool.devops.repair.mapper; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.chinaweal.youfool.devops.repair.controller.query.RepairTodoListQuery; +import com.chinaweal.youfool.devops.repair.entity.RepairHandle; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.chinaweal.youfool.devops.repair.entity.RepairTodo; +import org.apache.ibatis.annotations.Param; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +/** + *

+ * 运维报障处理流程记录 Mapper 接口 + *

+ * + * @author chinaweal + * @since 2020-06-05 + */ +public interface RepairHandleMapper extends BaseMapper { + + BigDecimal countStep(@Param("query") RepairTodoListQuery query, @Param("itemId") String itemId); + + /** + * 处理故障N次成功数量 + */ + BigDecimal countResultSecond(@Param("query") RepairTodoListQuery query, @Param("second") Integer second); + + /** + * 处理故障N次成功列表 + */ + IPage listResultSecond(Page page, @Param("query") RepairTodoListQuery query, @Param("second") Integer second); + + /** + * 平均解决时长 + */ + Map getAvgResolvedTime(@Param("query") RepairTodoListQuery query); + + /** + * 平均处理时长 + */ + Map getAvgFeedbackTime(@Param("query") RepairTodoListQuery query); + + /** + * 根据时间范围、机构、环节,统计流程数量,去重 + */ + Long countDistinctByTimeAndOrgAndStep(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime, + @Param("orgListLike") List orgListLike, @Param("step") String step); +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/mapper/RepairLabelMapper.java b/src/main/java/com/chinaweal/youfool/devops/repair/mapper/RepairLabelMapper.java new file mode 100644 index 0000000..786fa48 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/mapper/RepairLabelMapper.java @@ -0,0 +1,31 @@ +package com.chinaweal.youfool.devops.repair.mapper; + +import com.chinaweal.youfool.devops.repair.controller.query.RepairTodoListQuery; +import com.chinaweal.youfool.devops.repair.entity.RepairLabel; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Map; + +/** + *

+ * 运维单标签 Mapper 接口 + *

+ * + * @author chinaweal + * @since 2020-07-10 + */ +public interface RepairLabelMapper extends BaseMapper { + + List> listLabelOrder(); + + /** + * 统计分类名称出现的次数 + * + * @param query + */ + List> groupNameCount(@Param("query") RepairTodoListQuery query); + + List listNameByRepairId(@Param("repairId") String repairId); +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/mapper/RepairMapper.java b/src/main/java/com/chinaweal/youfool/devops/repair/mapper/RepairMapper.java new file mode 100644 index 0000000..8fe48fa --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/mapper/RepairMapper.java @@ -0,0 +1,25 @@ +package com.chinaweal.youfool.devops.repair.mapper; + +import com.chinaweal.youfool.devops.repair.controller.query.RepairTodoListQuery; +import com.chinaweal.youfool.devops.repair.entity.Repair; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Param; + +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + +/** + *

+ * 运维报障信息 Mapper 接口 + *

+ * + * @author chinaweal + * @since 2020-06-05 + */ +public interface RepairMapper extends BaseMapper { + + List> groupByQuestionTypeCount(@Param("query") RepairTodoListQuery query); + + BigDecimal countByQuestionType(@Param("query") RepairTodoListQuery query); +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/mapper/RepairSummaryMapper.java b/src/main/java/com/chinaweal/youfool/devops/repair/mapper/RepairSummaryMapper.java new file mode 100644 index 0000000..125ef59 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/mapper/RepairSummaryMapper.java @@ -0,0 +1,29 @@ +package com.chinaweal.youfool.devops.repair.mapper; + +import com.chinaweal.youfool.devops.repair.entity.RepairSummary; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Param; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +/** + *

+ * 运维报障统计汇总 Mapper 接口 + *

+ * + * @author chinaweal + * @since 2020-08-13 + */ +public interface RepairSummaryMapper extends BaseMapper { + + List> sumTotalByOrgAndDay(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime, + @Param("orgs") List orgs); + + List> getGroupQuestionTop(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime, + @Param("orgs") List orgs); + + List> sumTotalByOrgAndQuestionDay(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime, + @Param("questionType") String questionType, @Param("orgs") List orgs); +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/mapper/RepairTodoMapper.java b/src/main/java/com/chinaweal/youfool/devops/repair/mapper/RepairTodoMapper.java new file mode 100644 index 0000000..7f2c2bd --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/mapper/RepairTodoMapper.java @@ -0,0 +1,52 @@ +package com.chinaweal.youfool.devops.repair.mapper; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.chinaweal.youfool.devops.repair.controller.query.RepairTodoListQuery; +import com.chinaweal.youfool.devops.repair.entity.RepairTodo; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Param; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +/** + *

+ * 运维报障待办 Mapper 接口 + *

+ * + * @author chinaweal + * @since 2020-06-05 + */ +public interface RepairTodoMapper extends BaseMapper { + + IPage listTodo(Page page, RepairTodoListQuery query); + + IPage listByTodoId(Page page, String[] todoIds); + + /** + * 根据统计项ID 查询列表 + */ +// IPage listByItemId(Page page, RepairTodoListQuery query, String itemId); + + /** + * 查询业务统分类统计查询 + */ + List> groupByBusClassifyCount(@Param("query") RepairTodoListQuery query); + + /** + * 查询业务统环节统计查询 + */ + List> groupByBusStepCount(@Param("query") RepairTodoListQuery query); + + /** + * 根据搜索条件查询整体数据数据情况 + */ + Map getWhole(@Param("query") RepairTodoListQuery query); + + Long countByLaunchTimeAndLikeOrg(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime, + @Param("orgListLike") List orgListLike); + + List listSonOrgId(@Param("orgId") String orgId); +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/scheduled/SummaryScheduled.java b/src/main/java/com/chinaweal/youfool/devops/repair/scheduled/SummaryScheduled.java new file mode 100644 index 0000000..84194dd --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/scheduled/SummaryScheduled.java @@ -0,0 +1,94 @@ +package com.chinaweal.youfool.devops.repair.scheduled; + +import com.chinaweal.youfool.devops.base.service.IMonitorService; +import com.chinaweal.youfool.devops.repair.service.INotificationService; +import com.chinaweal.youfool.devops.repair.service.IRepairSummaryService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.io.IOException; +import java.time.LocalDate; + +/** + * 汇总统计定时任务 + */ +@Component +@Slf4j +public class SummaryScheduled { + + @Resource + private IRepairSummaryService iRepairSummaryService; + @Resource + private INotificationService iNotificationService; + @Resource + private IMonitorService iMonitorService; + + /** + * 按照天数格式和机构 汇总报障的记录参数 + * 每天零点5分开始跑,汇总昨天的一整天 + */ + @Transactional("devopsTransactionManager") + public void sumAllOrgByDay() { + log.info("--------开始:执行按照天数格式和机构 汇总报障的记录参数(每天零点5分开始跑,汇总昨天的一整天)----------"); + try { + iRepairSummaryService.sumAllOrgByDay(LocalDate.now().minusDays(1)); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + log.info("--------结束:执行按照天数格式和机构 汇总报障的记录参数(每天零点5分开始跑,汇总昨天的一整天)----------"); + } + + /** + * 按照天数格式和机构、问题分类 汇总报障的记录参数 + * 每20分钟全量更新一次,汇总之前所有数据至昨天 + */ + @Transactional("devopsTransactionManager") + public void sumAllOrgGroupQByDay() { + log.info("--------开始:按照天数格式和机构、问题分类 汇总报|障的记录参数(每20分钟全量更新一次,汇总之前所有数据至昨天) ----------"); + //佛山默认从6月1号, + LocalDate startDate = LocalDate.parse("2020-06-01"); + while (startDate.isBefore(LocalDate.now())) { + try { + iRepairSummaryService.sumAllOrgAndGroupQuestionByDay(startDate); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + startDate = startDate.plusDays(1); + } + log.info("--------结束:按照天数格式和机构、问题分类 汇总报障的记录参数(每20分钟全量更新一次,汇总之前所有数据至昨天) ----------"); + } + + /** + * 每月1号零点,统计上个月的通报记录 + */ + @Transactional("devopsTransactionManager") + public void sumMonthMakeData() { + log.info("--------开始:每月1号零点,统计上个月的通报记录 ----------"); + LocalDate date = LocalDate.now().minusMonths(1); + iNotificationService.makeData(date); + log.info("--------结束:每月1号零点,统计上个月的通报记录 ----------"); + } + + /** + * 每天8点进行通报,运维统计情况 + */ + @Transactional("devopsTransactionManager") + public void sendDayJournal() throws IOException { + log.info("--------开始:每天早上8点,通报一次运维记录 ----------"); + LocalDate date = LocalDate.now().minusDays(1); + iNotificationService.sendDayJournal(date); + log.info("--------结束:每天早上8点,通报一次运维记录 ----------"); + } + + /** + * 每天查询数据库密码过期情况,符合则进行通知预警 + */ + public void countDbPwdExpireAndSendWx() throws Exception { + log.info("--------开始:每天早上8点,查询账号密码过期情况 ----------"); + iMonitorService.countDbPwdExpireAndSendWx(); + log.info("--------结束:每天早上8点,查询账号密码过期情况 ----------"); + } + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/service/INotificationService.java b/src/main/java/com/chinaweal/youfool/devops/repair/service/INotificationService.java new file mode 100644 index 0000000..0b53435 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/service/INotificationService.java @@ -0,0 +1,48 @@ +package com.chinaweal.youfool.devops.repair.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.chinaweal.youfool.devops.repair.entity.Notification; + +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.IOException; +import java.time.LocalDate; +import java.util.List; +import java.util.Map; + +/** + *

+ * 通报 服务类 + *

+ * + * @author chinaweal + * @since 2020-11-02 + */ +public interface INotificationService extends IService { + + /** + * 导出通报文件word + */ + void exportBulletinWord(LocalDate parse, HttpServletResponse response) throws Exception; + + /** + * 根据月份生成通报数据 + */ + void makeData(LocalDate parse); + + List> findUnitData(LocalDate parse); + + /** + * 生成每日通报 + * + * @param date 统计的日期 + */ + File createDayJournalXlsx(LocalDate date); + + /** + * 发送通报,到企业微信 + * + * @param date 统计的日期 + */ + void sendDayJournal(LocalDate date) throws IOException; +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/service/IRepairFileService.java b/src/main/java/com/chinaweal/youfool/devops/repair/service/IRepairFileService.java new file mode 100644 index 0000000..20c6103 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/service/IRepairFileService.java @@ -0,0 +1,44 @@ +package com.chinaweal.youfool.devops.repair.service; + +import com.chinaweal.youfool.devops.repair.entity.RepairFile; +import com.baomidou.mybatisplus.extension.service.IService; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +/** + *

+ * 运维报障附件 服务类 + *

+ * + * @author chinaweal + * @since 2020-06-05 + */ +public interface IRepairFileService extends IService { + + /** + * 保存文件 + * + * @return + */ + Map loadFile(MultipartFile multipartFile, String tempRepairId, String type, String tempHandleId) throws IOException; + + /** + * 根据临时的repairId记录 修改最终的repairId、handleId + */ + void updateRepairAndHandleIdByTempRepairId(String tempRepairId, String repairId, String handleId); + + List listByRepairId(String repairId); + + void downloadFile(String uuid, boolean online, HttpServletResponse response) throws IOException; + + void deleteFile(String uuid); + + /** + * 根据临时的handleId记录 修改最终的repairId、handleId + */ + void updateHandleIdByTempHandleId(String tempHandleId, String handleId); +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/service/IRepairHandleService.java b/src/main/java/com/chinaweal/youfool/devops/repair/service/IRepairHandleService.java new file mode 100644 index 0000000..2e0ed0d --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/service/IRepairHandleService.java @@ -0,0 +1,63 @@ +package com.chinaweal.youfool.devops.repair.service; + +import com.chinaweal.youfool.devops.repair.entity.RepairHandle; +import com.baomidou.mybatisplus.extension.service.IService; +import com.chinaweal.youfool.framework.springboot.rest.RestResult; + +import java.util.List; + +/** + *

+ * 运维报障处理流程记录 服务类 + *

+ * + * @author chinaweal + * @since 2020-06-05 + */ +public interface IRepairHandleService extends IService { + /** + * 已报障 + */ + String DECLARE = "declare"; + /** + * 分派 + */ + String ASSIGN = "assign"; + /** + * 处理中 + */ + String HANDLE = "handle"; + /** + * 已处理 + */ + String FEEDBACK = "feedback"; + /** + * 未解决 + */ + String UNRESOLVED = "unresolved"; + /** + * 已解决 + */ + String RESOLVED = "resolved"; + /** + * 结束 + */ + String END = "end"; + + /** + * 更新处理流程记录 + */ + RepairHandle updateByRepairIdHandleTodo(RepairHandle repairHandle); + + /** + * 查询处理流程记录,生成时间降序 + */ + List listByRepairId(String repairId); + + /** + * 获取当前处理流程记录 + */ + RepairHandle getCurrentHandle(String repairId); + + RestResult unresolvedHandle(RepairHandle repairHandle, String tempHandleId); +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/service/IRepairLabelService.java b/src/main/java/com/chinaweal/youfool/devops/repair/service/IRepairLabelService.java new file mode 100644 index 0000000..b5c0a21 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/service/IRepairLabelService.java @@ -0,0 +1,23 @@ +package com.chinaweal.youfool.devops.repair.service; + +import com.chinaweal.youfool.devops.repair.controller.query.RepairTodoListQuery; +import com.chinaweal.youfool.devops.repair.entity.RepairLabel; +import com.baomidou.mybatisplus.extension.service.IService; + +import java.util.List; +import java.util.Map; + +/** + *

+ * 运维单标签 服务类 + *

+ * + * @author chinaweal + * @since 2020-07-10 + */ +public interface IRepairLabelService extends IService { + + List> listLabel(); + + List> groupLabelCount(RepairTodoListQuery query); +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/service/IRepairService.java b/src/main/java/com/chinaweal/youfool/devops/repair/service/IRepairService.java new file mode 100644 index 0000000..5c7ff17 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/service/IRepairService.java @@ -0,0 +1,54 @@ +package com.chinaweal.youfool.devops.repair.service; + +import com.chinaweal.youfool.devops.repair.controller.query.RepairTodoListQuery; +import com.chinaweal.youfool.framework.springboot.rest.RestResult; +import com.chinaweal.youfool.devops.repair.entity.Repair; +import com.baomidou.mybatisplus.extension.service.IService; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +/** + *

+ * 运维报障信息 服务类 + *

+ * + * @author chinaweal + * @since 2020-06-05 + */ +public interface IRepairService extends IService { + + RestResult saveRepair(Repair repair); + + RestResult updateRepair(Repair repair); + + Repair getRepair(String repairId); + + /** + * 根据标签类型修改标签 + */ + void updateLabelByType(List repairIds, String labelType, String labelName); + + /** + * 统计各项报障数据内容 + */ + List> sumSummary(RepairTodoListQuery query); + + /** + * 根据业务标签类型进行统计 + */ + List> sumBusLabelByType(RepairTodoListQuery query, String labelType); + + /** + * 导出统计项的内容 + */ + void exportSumSummary(RepairTodoListQuery query, HttpServletResponse response) throws IOException; + + /** + * 更新部分运维信息 + */ + void updateDevInfo(Map map); + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/service/IRepairSummaryService.java b/src/main/java/com/chinaweal/youfool/devops/repair/service/IRepairSummaryService.java new file mode 100644 index 0000000..32e2bcd --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/service/IRepairSummaryService.java @@ -0,0 +1,61 @@ +package com.chinaweal.youfool.devops.repair.service; + +import com.chinaweal.youfool.devops.repair.entity.RepairSummary; +import com.baomidou.mybatisplus.extension.service.IService; +import org.apache.commons.lang3.ArrayUtils; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + *

+ * 运维报障统计汇总 服务类 + *

+ * + * @author chinaweal + * @since 2020-08-13 + */ +public interface IRepairSummaryService extends IService { + /** + * 机构统计 + */ + String ORG = "org"; + + /** + * 机构+问题分类 统计 + */ + String ORG_QUESTION = "orgQuestion"; + + + /** + * 根据机构和天,汇总报障相关数量 + * + * @param day + */ + void sumAllOrgByDay(LocalDate day); + + /** + * 根据机构,问题分类天,汇总报障相关数量 + * + * @param day + */ + void sumAllOrgAndGroupQuestionByDay(LocalDate day); + + + static List getOrgNameList() { + + List orgList = new ArrayList<>(); + orgList.add("佛山市市场监督管理局"); + orgList.add("佛山市禅城区市场监督管理局"); + orgList.add("佛山市顺德区市场监督管理局"); + orgList.add("佛山市南海区市场监督管理局"); + orgList.add("佛山市三水区市场监督管理局"); + orgList.add("佛山市高明区市场监督管理局"); + orgList.add("考试中心"); + + return orgList; + } +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/service/IRepairTodoService.java b/src/main/java/com/chinaweal/youfool/devops/repair/service/IRepairTodoService.java new file mode 100644 index 0000000..2c3ce3f --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/service/IRepairTodoService.java @@ -0,0 +1,113 @@ +package com.chinaweal.youfool.devops.repair.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.chinaweal.youfool.devops.repair.controller.query.RepairTodoListQuery; +import com.chinaweal.youfool.devops.repair.entity.Repair; +import com.chinaweal.youfool.devops.repair.entity.RepairHandle; +import com.chinaweal.youfool.devops.repair.entity.RepairTodo; +import com.baomidou.mybatisplus.extension.service.IService; +import com.chinaweal.youfool.framework.springboot.rest.RestResult; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.time.LocalDate; +import java.util.List; +import java.util.Map; + +/** + *

+ * 运维报障待办 服务类 + *

+ * + * @author chinaweal + * @since 2020-06-05 + */ +public interface IRepairTodoService extends IService { + + RepairTodo getByRepairId(String repairId); + + IPage findList(RepairTodoListQuery query); + + /** + * 生成待办 + */ + RepairTodo generateTodo(Repair repair); + + RepairTodo updateTodo(Repair repair); + + /** + * 根据条件导出待办数据 + */ + void exportTodo(RepairTodoListQuery query, HttpServletResponse response, String type) throws IOException; + + RestResult assign(RepairHandle repairHandle); + + /** + * 添加生成下一步流程记录,和更新表单和待办 + */ + RestResult generateNextHandle(RepairHandle repairHandle); + + /** + * 根据申报账号,查询统计的数据 + * + * @param username + * @return + */ + Map countRepairStepByUserId(String username); + + RestResult feedback(RepairHandle repairHandle, String fileHandleId); + + /** + * 工程师查询自定导出表头列表 + */ + Map excelDevFields(); + + /** + * 业务人员查询自定导出表头列表 + */ + Map excelBusinessFields(); + + /** + * 运维单催单 + * + * @param repairId + * @return + */ + RestResult reminder(String repairId); + + /** + * 根据权限查询用户列表 + */ + IPage synthesizeBusinessList(RepairTodoListQuery query); + + /** + * 工程师获取代办列表 + */ + IPage findTodoByEngineer(RepairTodoListQuery query); + + /** + * 业务人员获取代办列表 + */ + IPage findTodoByBusiness(RepairTodoListQuery query); + + IPage listByItemId(RepairTodoListQuery query, String itemId); + + /** + * 导出统计项内容 + */ + void exportListByItemId(HttpServletResponse response, RepairTodoListQuery query, String itemId, String type) throws IOException; + + /** + * 综合查询 + */ + IPage synthesizeEngineerList(RepairTodoListQuery query); + + IPage leaderTodo(RepairTodoListQuery query); + + /** + * 批量分派 + * @param repairHandleList 运维单集合 + * @return + */ + RestResult batchAssign(List repairHandleList); +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/service/impl/NotificationServiceImpl.java b/src/main/java/com/chinaweal/youfool/devops/repair/service/impl/NotificationServiceImpl.java new file mode 100644 index 0000000..97e39c3 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/service/impl/NotificationServiceImpl.java @@ -0,0 +1,537 @@ +package com.chinaweal.youfool.devops.repair.service.impl; + +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.enums.WriteDirectionEnum; +import com.alibaba.excel.write.metadata.WriteSheet; +import com.alibaba.excel.write.metadata.fill.FillConfig; +import com.alibaba.excel.write.metadata.fill.FillWrapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.chinaweal.youfool.devops.repair.api.RobotApi; +import com.chinaweal.youfool.devops.repair.controller.query.RepairTodoListQuery; +import com.chinaweal.youfool.devops.repair.entity.Notification; +import com.chinaweal.youfool.devops.repair.entity.RepairTodo; +import com.chinaweal.youfool.devops.repair.mapper.NotificationMapper; +import com.chinaweal.youfool.devops.repair.mapper.RepairHandleMapper; +import com.chinaweal.youfool.devops.repair.service.INotificationService; +import com.chinaweal.youfool.devops.repair.service.IRepairHandleService; +import com.chinaweal.youfool.devops.repair.service.IRepairSummaryService; +import com.chinaweal.youfool.devops.repair.service.IRepairTodoService; +import com.spire.xls.Workbook; +import com.spire.xls.Worksheet; +import freemarker.template.Configuration; +import freemarker.template.Template; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.io.IOUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import javax.imageio.ImageIO; +import javax.servlet.http.HttpServletResponse; +import java.awt.image.BufferedImage; +import java.io.*; +import java.math.BigDecimal; +import java.nio.charset.StandardCharsets; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.TemporalAdjusters; +import java.util.*; + +/** + *

+ * 通报 服务实现类 + *

+ * + * @author chinaweal + * @since 2020-11-02 + */ +@Service +public class NotificationServiceImpl extends ServiceImpl implements INotificationService { + @Resource + private RepairHandleMapper repairHandleMapper; + @Resource + private RobotApi robotApi; + @Value("${file.devopsDir}") + private String devopsDir; + @Value("${noticeWebhookKeys}") + private String[] noticeWebhookKeys; + @Resource + private IRepairTodoService iRepairTodoService; + + @Override + public void exportBulletinWord(LocalDate date, HttpServletResponse response) throws Exception { + date = date.with(TemporalAdjusters.firstDayOfMonth()); + String templateDir = this.getClass().getResource("/word").getPath(); + + Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS); + configuration.setDirectoryForTemplateLoading(new File(templateDir)); + configuration.setDefaultEncoding("utf-8"); + Template template = configuration.getTemplate("yunWeiTongGao.xml"); + Map dataModel = new LinkedHashMap<>(); + + //日期 + dataModel.put("year", date.getYear()); + dataModel.put("month", date.getMonthValue()); + dataModel.put("day", date.getDayOfMonth()); + dataModel.put("currYear", LocalDate.now().getYear()); + dataModel.put("currMonth", LocalDate.now().getMonthValue()); + dataModel.put("currDay", LocalDate.now().getDayOfMonth()); + + unitSituation(dataModel, date); + + // 设置下载文档名称 + String fileName = new String(("佛山市市场监督管理局关于佛山市市场监管许可登记一体化系统" + date.getYear() + "年" + date.getMonthValue() + "月运维情况的通报").getBytes(StandardCharsets.UTF_8), + StandardCharsets.ISO_8859_1); + //设置:当浏览器收到这份资源的时候,以下载的方式提醒用户,而不是直接显示 + response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + ".doc\""); + Writer out = new BufferedWriter(new OutputStreamWriter(response.getOutputStream(), StandardCharsets.UTF_8)); + + // 调用模板对象的process方法输出文件。 + template.process(dataModel, out); + // 第八步:关闭流。 + out.close(); + } + + @Override + public void makeData(LocalDate date) { + LocalDateTime start = LocalDateTime.of(date.with(TemporalAdjusters.firstDayOfMonth()), LocalTime.MIN); + LocalDateTime end = LocalDateTime.of(date.with(TemporalAdjusters.lastDayOfMonth()), LocalTime.MAX); + + List orgNameList = IRepairSummaryService.getOrgNameList(); + for (String org : orgNameList) { + Notification notification = new Notification(); + notification.setOrg(org); + notification.setMonthDate(start.toLocalDate()); + //获取历史数 + RepairTodoListQuery query = new RepairTodoListQuery(); + query.setLaunchTimeEnd(end); + query.setOrgListLike(Collections.singletonList(org)); + + BigDecimal historyTotal = repairHandleMapper.countStep(query, "total"); + BigDecimal historyConfirmed = repairHandleMapper.countStep(query, "confirmed"); + BigDecimal historyResolved = repairHandleMapper.countStep(query, "resolved"); + BigDecimal historyUntreated = repairHandleMapper.countStep(query, "untreated"); + notification.setHistoryTotal(historyTotal); + notification.setHistoryConfirmed(historyConfirmed); + notification.setHistoryResolved(historyResolved); + notification.setHistoryUntreated(historyUntreated); + //当前月 + query.setLaunchTimeStart(start); + BigDecimal total = repairHandleMapper.countStep(query, "total"); + BigDecimal confirmed = repairHandleMapper.countStep(query, "confirmed"); + BigDecimal resolved = repairHandleMapper.countStep(query, "resolved"); + BigDecimal untreated = repairHandleMapper.countStep(query, "untreated"); + notification.setTotal(total); + notification.setConfirmed(confirmed); + notification.setResolved(resolved); + notification.setUntreated(untreated); + + //处理次数 + BigDecimal oneSuccess = repairHandleMapper.countResultSecond(query, 1); + BigDecimal twoSuccess = repairHandleMapper.countResultSecond(query, 2); + BigDecimal threeSuccess = repairHandleMapper.countResultSecond(query, 3); + notification.setOne(oneSuccess); + notification.setTwo(twoSuccess); + notification.setThree(threeSuccess); + //平均处理时长 + Map avgFeedbackMap = repairHandleMapper.getAvgFeedbackTime(query); + BigDecimal feedbackHour = (BigDecimal) avgFeedbackMap.get("feedbackHour"); + BigDecimal feedbackNumber = (BigDecimal) avgFeedbackMap.get("feedbackNumber"); + BigDecimal avgHandle = feedbackNumber.compareTo(BigDecimal.valueOf(0)) > 0 ? feedbackHour.divide(feedbackNumber, 2, BigDecimal.ROUND_HALF_UP) : BigDecimal.valueOf(0); + notification.setAvgHandle(avgHandle); + //平均解决时长 + Map avgResolvedMap = repairHandleMapper.getAvgResolvedTime(query); + BigDecimal resolvedHour = (BigDecimal) avgResolvedMap.get("resolvedHour"); + BigDecimal resolvedNumber = (BigDecimal) avgResolvedMap.get("resolvedNumber"); + BigDecimal avgResolved = resolvedNumber.compareTo(BigDecimal.valueOf(0)) > 0 ? resolvedHour.divide(resolvedNumber, 2, BigDecimal.ROUND_HALF_UP) : BigDecimal.valueOf(0); + notification.setAvgResolved(avgResolved); + + save(notification); + } + + } + + @Override + public List> findUnitData(LocalDate date) { + List> list = new ArrayList<>(); + List orgNameList = IRepairSummaryService.getOrgNameList(); + //本月 + for (String org : orgNameList) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(Notification::getMonthDate, date); + lqw.eq(Notification::getOrg, org); + Notification notification = getOne(lqw, false); + //其中一个单位为空,跳出 + if (notification == null) { + return new ArrayList<>(); + } + Map map = new HashMap<>(); + map.put("name", org); + map.put("total", notification.getTotal()); + map.put("resolved", notification.getResolved()); + map.put("feedback", notification.getConfirmed()); + map.put("untreated", notification.getUntreated()); + list.add(map); + } + return list; + } + + @Override + public File createDayJournalXlsx(LocalDate date) { + Map data = new HashMap<>(); + List> handleList;//当天人员处理列表 + List> unhandledList = new ArrayList<>();//未处理运维单人员分布 + //新增数 + LambdaQueryWrapper lqwn = Wrappers.lambdaQuery(); + lqwn.between(RepairTodo::getLaunchTime, date, date.plusDays(1)); + int dailyNewly = iRepairTodoService.count(lqwn); + //已处理数 + LambdaQueryWrapper lqwh = Wrappers.lambdaQuery(); + lqwh.between(RepairTodo::getLaunchTime, date, date.plusDays(1)); + lqwh.in(RepairTodo::getStep, IRepairHandleService.FEEDBACK, IRepairHandleService.RESOLVED); + int dailyHandled = iRepairTodoService.count(lqwh); + //未处理数 + LambdaQueryWrapper lqwu = Wrappers.lambdaQuery(); + lqwu.between(RepairTodo::getLaunchTime, date, date.plusDays(1)); + lqwu.in(RepairTodo::getStep, IRepairHandleService.DECLARE, IRepairHandleService.ASSIGN, IRepairHandleService.HANDLE, + IRepairHandleService.UNRESOLVED); + int dailyUntreated = iRepairTodoService.count(lqwu); + //归档数 + LambdaQueryWrapper lqwc = Wrappers.lambdaQuery(); + lqwc.between(RepairTodo::getLaunchTime, date, date.plusDays(1)); + lqwc.eq(RepairTodo::getStep, IRepairHandleService.RESOLVED); + int dailyConclude = iRepairTodoService.count(lqwc); + //待确认数 + LambdaQueryWrapper lqwcf = Wrappers.lambdaQuery(); + lqwcf.between(RepairTodo::getLaunchTime, date, date.plusDays(1)); + lqwcf.eq(RepairTodo::getStep, IRepairHandleService.FEEDBACK); + int dailyConfirmed = iRepairTodoService.count(lqwcf); + + data.put("date", date.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日"))); + data.put("createTime", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); + data.put("dailyNewly", dailyNewly);//新增数 + data.put("dailyHandled", dailyHandled);//已处理数 + data.put("dailyUntreated", dailyUntreated);//未处理数 + data.put("dailyConclude", dailyConclude);//归档数 + data.put("dailyConfirmed", dailyConfirmed);//待确认数 + data.put("dailyRate", percentage(BigDecimal.valueOf(dailyHandled), BigDecimal.valueOf(dailyNewly)));//处理完成率 + + //总量统计 + LambdaQueryWrapper lqwT = Wrappers.lambdaQuery(); + int total = iRepairTodoService.count(lqwT); + data.put("total", total);//运维单总数 + + LambdaQueryWrapper lqwTh = Wrappers.lambdaQuery(); + lqwTh.in(RepairTodo::getStep, IRepairHandleService.FEEDBACK, IRepairHandleService.RESOLVED); + int handled = iRepairTodoService.count(lqwTh); + data.put("handled", handled);//已处理数 + + LambdaQueryWrapper lqwTu = Wrappers.lambdaQuery(); + lqwTu.in(RepairTodo::getStep, IRepairHandleService.DECLARE, IRepairHandleService.ASSIGN, IRepairHandleService.HANDLE, + IRepairHandleService.UNRESOLVED); + int untreated = iRepairTodoService.count(lqwTu); + data.put("untreated", untreated);//未处理数 + + //当天人员处理列表 + LambdaQueryWrapper lqwhl = Wrappers.lambdaQuery(); + lqwhl.between(RepairTodo::getFeedbackTime, date, date.plusDays(1)); + int dailyTotal = iRepairTodoService.count(lqwhl);//当天总处理量 + handleList = baseMapper.dailyHandledUserNum(date, date.plusDays(1)); + for (int i = 0; i < handleList.size(); i++) { + Map map = handleList.get(i); + map.put("index", i + 1); + map.put("rate", percentage((BigDecimal) map.get("num"), BigDecimal.valueOf(dailyTotal))); + } + + //未处理运维单人员分布 + LambdaQueryWrapper lqwul = Wrappers.lambdaQuery(); + lqwul.in(RepairTodo::getStep, IRepairHandleService.DECLARE, IRepairHandleService.ASSIGN, IRepairHandleService.HANDLE, + IRepairHandleService.UNRESOLVED); + int utotal = iRepairTodoService.count(lqwul);//总量 + unhandledList = baseMapper.unhandledUserNum(); + for (int i = 0; i < unhandledList.size(); i++) { + Map map = unhandledList.get(i); + map.put("index", i + 1); + map.putIfAbsent("engineer", "待分派的单"); + map.put("rate", percentage((BigDecimal) map.get("num"), BigDecimal.valueOf(utotal))); + } + String pathname = devopsDir + File.separator + "notification"; + new File(pathname).mkdirs(); + File file = new File(pathname + File.separator + date + ".xlsx"); + //填充表格 + String templateFileName = this.getClass().getClassLoader().getResource("template/daily-report.xlsx").getPath(); + ExcelWriter excelWriter = EasyExcel.write(file).withTemplate(templateFileName).build(); + FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).direction(WriteDirectionEnum.VERTICAL).build(); + + WriteSheet summaryWriteSheet = EasyExcel.writerSheet("每日通报").build(); + // 如果有多个list 模板上必须有{前缀.} 这里的前缀就是 data1,然后多个list必须用 FillWrapper包裹 + excelWriter.fill(new FillWrapper("handleList", handleList), fillConfig, summaryWriteSheet); + excelWriter.fill(new FillWrapper("unhandledList", unhandledList), fillConfig, summaryWriteSheet); + excelWriter.fill(data, summaryWriteSheet); + + // 别忘记关闭流 + excelWriter.finish(); + return file; + } + + @Override + public void sendDayJournal(LocalDate date) throws IOException { + File file = createDayJournalXlsx(date); + Workbook workbook = new Workbook(); + workbook.loadFromFile(file.getPath()); + //设置x轴、y轴dpi + workbook.getConverterSetting().setXDpi(3000); + workbook.getConverterSetting().setYDpi(3000); + //获取第一张工作表 + Worksheet sheet = workbook.getWorksheets().get("每日通报"); + int lastRow = sheet.getLastRow(); + int lastColumn = sheet.getLastColumn(); + //保存到图片 注意:当图片大小展示有问题时,可以调整分辨为100% + BufferedImage bufferedImage = sheet.toImage(2, 2, lastRow, lastColumn); + //创建临时文件 + File pngFile = File.createTempFile(file.getName(), ".png"); + ImageIO.write(bufferedImage, "PNG", pngFile); + Map image = new HashMap<>(); + FileInputStream inPng = new FileInputStream(pngFile); + byte[] bytes = IOUtils.toByteArray(inPng); + inPng.read(bytes); + String base64 = Base64.getEncoder().encodeToString(bytes); + String md5 = DigestUtils.md5Hex(bytes); + image.put("base64", base64); + image.put("md5", md5); + + Map query = new HashMap<>(); + query.put("msgtype", "image"); + query.put("image", image); + + for (String webhookKey : noticeWebhookKeys) { + Map data = robotApi.webhookSend(query, webhookKey); + } + + inPng.close(); + pngFile.delete(); + } + + /** + * 佛山通报各单位报障情况数据 + */ + public void unitSituation(Map dataModel, LocalDate date) { + LocalDate monthDate = date.with(TemporalAdjusters.firstDayOfMonth()); + LocalDate end = monthDate.with(TemporalAdjusters.lastDayOfMonth()); + Map orgMap = new LinkedHashMap<>(); + orgMap.put("cityData", "佛山市市场监督管理局"); + orgMap.put("chanChengData", "佛山市禅城区市场监督管理局"); + orgMap.put("shunDeData", "佛山市顺德区市场监督管理局"); + orgMap.put("gaoMingData", "佛山市高明区市场监督管理局"); + orgMap.put("sanShuiData", "佛山市三水区市场监督管理局"); + orgMap.put("nanHaiData", "佛山市南海区市场监督管理局"); + + BigDecimal sumTotal = new BigDecimal(0); + BigDecimal sumResolved = new BigDecimal(0); + BigDecimal sumUntreated = new BigDecimal(0); + BigDecimal sumConfirmed = new BigDecimal(0); + BigDecimal sumHistoryTotal = new BigDecimal(0); + BigDecimal sumHistoryConfirmed = new BigDecimal(0); + BigDecimal sumHistoryUntreated = new BigDecimal(0); + BigDecimal lastTotal = new BigDecimal(0); + BigDecimal lastResolved = new BigDecimal(0); + BigDecimal lastConfirmed = new BigDecimal(0); + BigDecimal lastUntreated = new BigDecimal(0); + BigDecimal lastHistoryUntreated = new BigDecimal(0); + BigDecimal lastHistoryTotal = new BigDecimal(0); + BigDecimal oneSuccess = new BigDecimal(0); + BigDecimal twoSuccess = new BigDecimal(0); + BigDecimal threeSuccess = new BigDecimal(0); + BigDecimal lastOneSuccess = new BigDecimal(0); + BigDecimal lastTwoSuccess = new BigDecimal(0); + BigDecimal lastThreeSuccess = new BigDecimal(0); + BigDecimal duration = new BigDecimal(0); + BigDecimal lastDuration = new BigDecimal(0); + + //遍历各单位获取数据 + for (Map.Entry entry : orgMap.entrySet()) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(Notification::getMonthDate, monthDate); + lqw.eq(Notification::getOrg, entry.getValue()); + + //本月 + Notification notification = getOne(lqw, false); + + Map data = new LinkedHashMap<>(); + data.put("total", notification.getTotal()); + data.put("resolvedTotal", notification.getResolved()); + data.put("resolvedProportion", percentage(notification.getResolved(), notification.getTotal())); + data.put("confirmedTotal", notification.getConfirmed()); + data.put("confirmedProportion", percentage(notification.getConfirmed(), notification.getTotal())); + data.put("untreated", notification.getUntreated()); + data.put("historyTotal", notification.getHistoryTotal()); + data.put("historyConfirmed", notification.getHistoryConfirmed()); + data.put("historyConfirmedProportion", percentage(notification.getHistoryConfirmed(), notification.getHistoryTotal())); + + dataModel.put(entry.getKey(), data); + + sumTotal = sumTotal.add(notification.getTotal()); + sumResolved = sumResolved.add(notification.getResolved()); + sumUntreated = sumUntreated.add(notification.getUntreated()); + sumConfirmed = sumConfirmed.add(notification.getConfirmed()); + sumHistoryTotal = sumHistoryTotal.add(notification.getHistoryTotal()); + sumHistoryConfirmed = sumHistoryConfirmed.add(notification.getHistoryConfirmed()); + sumHistoryUntreated = sumHistoryUntreated.add(notification.getHistoryUntreated()); + + oneSuccess = oneSuccess.add(notification.getOne()); + twoSuccess = twoSuccess.add(notification.getTwo()); + threeSuccess = threeSuccess.add(notification.getThree()); + + duration = duration.add(notification.getAvgHandle()); + + //上一月 + lqw = Wrappers.lambdaQuery(); + lqw.eq(Notification::getMonthDate, monthDate.minusMonths(1)); + lqw.eq(Notification::getOrg, entry.getValue()); + Notification lastNotification = getOne(lqw, false); + + lastTotal = lastTotal.add(lastNotification.getTotal()); + lastResolved = lastResolved.add(lastNotification.getResolved()); + lastUntreated = lastUntreated.add(lastNotification.getUntreated()); + lastConfirmed = lastConfirmed.add(lastNotification.getConfirmed()); + lastHistoryUntreated = lastHistoryUntreated.add(lastNotification.getHistoryUntreated()); + lastHistoryTotal = lastHistoryTotal.add(lastNotification.getHistoryTotal()); + + lastOneSuccess = lastOneSuccess.add(lastNotification.getOne()); + lastTwoSuccess = lastTwoSuccess.add(lastNotification.getTwo()); + lastThreeSuccess = lastThreeSuccess.add(lastNotification.getThree()); + + lastDuration = lastDuration.add(lastNotification.getAvgHandle()); + } + + //合计 + Map allData = new LinkedHashMap<>(); + allData.put("total", sumTotal); + allData.put("resolvedTotal", sumResolved); + allData.put("resolvedProportion", percentage(sumResolved, sumTotal)); + allData.put("confirmedTotal", sumConfirmed); + allData.put("confirmedProportion", percentage(sumConfirmed, sumTotal)); + allData.put("untreated", sumUntreated); + allData.put("historyTotal", sumHistoryTotal); + allData.put("historyConfirmed", sumHistoryConfirmed); + allData.put("historyConfirmedProportion", percentage(sumHistoryConfirmed, sumHistoryTotal)); + dataModel.put("allData", allData); + + //一、各单位报障情况 + dataModel.put("reportTotal", sumTotal); + dataModel.put("average", sumTotal.divide(BigDecimal.valueOf(end.getDayOfMonth()), 1, BigDecimal.ROUND_HALF_UP)); + dataModel.put("byMonth", date.getMonthValue()); + dataModel.put("byDay", end.getDayOfMonth()); + dataModel.put("processed", sumConfirmed.add(sumResolved)); + dataModel.put("resolved", sumResolved); + dataModel.put("confirmed", sumConfirmed); + + String processedProportion = percentage(sumConfirmed.add(sumResolved), sumTotal); + String lastProcessedProportion = percentage(lastConfirmed.add(lastResolved), lastTotal); + dataModel.put("processedProportion", processedProportion); + dataModel.put("untreated", sumUntreated); + + // 上个月数据 + String reportQoq = percentage(sumTotal.subtract(lastTotal), lastTotal); + dataModel.put("reportQoq", handleQoq(reportQoq)); + dataModel.put("processedQoq", handleQoq(subtractPercentage(processedProportion, lastProcessedProportion))); + + + //二、众望通报障解决情况 + String untreatedProportion = percentage(sumUntreated, sumTotal); + String lastUntreatedProportion = percentage(lastUntreated, lastTotal); + dataModel.put("untreatedProportion", untreatedProportion); + dataModel.put("untreatedQoq", handleQoq(subtractPercentage(untreatedProportion, lastUntreatedProportion))); + dataModel.put("historyTotal", sumHistoryTotal); + dataModel.put("historyUntreated", sumHistoryUntreated); + + String historyUntreatedProportion = percentage(sumHistoryUntreated, sumHistoryTotal); + dataModel.put("historyUntreatedProportion", historyUntreatedProportion); + + String lastHistoryUntreatedProportion = percentage(lastHistoryUntreated, lastHistoryTotal); + dataModel.put("historyUntreatedQoq", handleQoq(subtractPercentage(historyUntreatedProportion, lastHistoryUntreatedProportion))); + + BigDecimal handleTotal = oneSuccess.add(twoSuccess).add(threeSuccess); + + //上一个月的 + BigDecimal lastHandleTotal = lastOneSuccess.add(lastTwoSuccess).add(lastThreeSuccess); + + //一次处理 + Map oneHandle = new LinkedHashMap<>(); + oneHandle.put("total", oneSuccess); + String oneProportion = percentage(oneSuccess, handleTotal); + String oneLastProportion = percentage(lastOneSuccess, lastHandleTotal); + oneHandle.put("proportion", oneProportion); + oneHandle.put("lastProportion", oneLastProportion); + + String oneQoq = subtractPercentage(oneProportion, oneLastProportion); + oneHandle.put("qoq", handleQoq(oneQoq)); + oneHandle.put("qoqTable", oneQoq); + + dataModel.put("oneHandle", oneHandle); + + //二次处理 + Map twoHandle = new LinkedHashMap<>(); + twoHandle.put("total", twoSuccess); + String twoProportion = percentage(twoSuccess, handleTotal); + String twoLastProportion = percentage(lastTwoSuccess, lastHandleTotal); + twoHandle.put("proportion", twoProportion); + twoHandle.put("lastProportion", twoLastProportion); + String twoQoq = subtractPercentage(twoProportion, twoLastProportion); + twoHandle.put("qoq", handleQoq(twoQoq)); + twoHandle.put("qoqTable", twoQoq); + dataModel.put("twoHandle", twoHandle); + + //三次处理 + Map threeHandle = new LinkedHashMap<>(); + threeHandle.put("total", threeSuccess); + + String threeProportion = percentage(threeSuccess, handleTotal); + String threeLastProportion = percentage(lastThreeSuccess, lastHandleTotal); + threeHandle.put("proportion", threeProportion); + threeHandle.put("lastProportion", threeLastProportion); + + String treeQoq = subtractPercentage(threeProportion, threeLastProportion); + threeHandle.put("qoq", handleQoq(treeQoq)); + threeHandle.put("qoqTable", treeQoq); + dataModel.put("threeHandle", threeHandle); + + //各单位平均时长累加还要除于单位数据 + duration = duration.divide(BigDecimal.valueOf(orgMap.size()), 2, BigDecimal.ROUND_HALF_UP); + lastDuration = lastDuration.divide(BigDecimal.valueOf(orgMap.size()), 2, BigDecimal.ROUND_HALF_UP); + + dataModel.put("duration", duration); + BigDecimal durationAvg = duration.divide(BigDecimal.valueOf(24), 1, BigDecimal.ROUND_HALF_UP); + BigDecimal lastDurationAvg = lastDuration.divide(BigDecimal.valueOf(24), 1, BigDecimal.ROUND_HALF_UP); + dataModel.put("durationAvg", durationAvg.stripTrailingZeros().toPlainString()); + + String durationQoq = percentage(durationAvg.subtract(lastDurationAvg), lastDurationAvg); + dataModel.put("durationQoq", handleQoq(durationQoq)); + dataModel.put("handleTotal", handleTotal); + } + + private String percentage(BigDecimal molecule, BigDecimal divisor) { + if (divisor.compareTo(BigDecimal.valueOf(0)) <= 0) { + return "0%"; + } + return molecule.multiply(BigDecimal.valueOf(100)).divide(divisor, 1, BigDecimal.ROUND_HALF_UP) + "%"; + } + + private String subtractPercentage(String minuendStr, String subtrahendStr) { + BigDecimal minuend = new BigDecimal(minuendStr.replace("%", "")); + BigDecimal subtrahend = new BigDecimal(subtrahendStr.replace("%", "")); + return minuend.subtract(subtrahend) + "%"; + } + + /** + * 处理环比,改成增加或减少 + */ + private String handleQoq(String qoq) { + return qoq.startsWith("-") ? "减少" + qoq.substring(1) : "增加" + qoq; + } +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/service/impl/RepairFileServiceImpl.java b/src/main/java/com/chinaweal/youfool/devops/repair/service/impl/RepairFileServiceImpl.java new file mode 100644 index 0000000..0a3fd07 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/service/impl/RepairFileServiceImpl.java @@ -0,0 +1,156 @@ +package com.chinaweal.youfool.devops.repair.service.impl; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.date.TimeInterval; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.chinaweal.youfool.devops.repair.entity.RepairFile; +import com.chinaweal.youfool.devops.repair.mapper.RepairFileMapper; +import com.chinaweal.youfool.devops.repair.service.IRepairFileService; +import lombok.extern.slf4j.Slf4j; +import net.coobird.thumbnailator.Thumbnails; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +/** + *

+ * 运维报障附件 服务实现类 + *

+ * + * @author chinaweal + * @since 2020-06-05 + */ +@Service +@Slf4j +public class RepairFileServiceImpl extends ServiceImpl implements IRepairFileService { + + @Value("${file.devopsDir}") + private String devopsDir; + + @Override + public Map loadFile(MultipartFile multipartFile, String repairId, String type, String tempHandleId) throws IOException { + RepairFile repairFile = new RepairFile(); + + repairFile.setRepairId(StringUtils.isNotBlank(repairId) ? repairId : UUID.randomUUID().toString().replace("-", "")); + repairFile.setFileName(multipartFile.getOriginalFilename()); + repairFile.setFileType(multipartFile.getContentType()); + repairFile.setType(type); + repairFile.setHandleId(tempHandleId); + repairFile.setUploadTime(LocalDateTime.now()); + int i = multipartFile.getOriginalFilename().lastIndexOf("."); + String filePathName = UUID.randomUUID().toString(); + if (i > 0) { + filePathName += multipartFile.getOriginalFilename().substring(i); + } + repairFile.setFilePath(filePathName); + + File dir = new File(devopsDir); + dir.mkdirs(); + File file = new File(devopsDir + File.separator + filePathName); + try (InputStream is = multipartFile.getInputStream();) { + if (StringUtils.containsIgnoreCase(multipartFile.getContentType(), "image") + && multipartFile.getSize() >= 2 * 1024 * 1024) { // 大于2M进行压缩 + //压缩图片 + TimeInterval timer = DateUtil.timer(); + Thumbnails.of(is).scale(1f).outputQuality(0.5f).toFile(file); + log.debug("图片压缩耗时: {} ms", timer.interval()); + } else { + multipartFile.transferTo(file); + } + } catch (IOException e) { + log.error("上传出错", e); + throw new RuntimeException(e.getMessage()); + } + repairFile.setFileSize(file.length()); + save(repairFile); + + Map body = new LinkedHashMap<>(); + body.put("uuid", repairFile.getUuid()); + body.put("repairId", repairFile.getRepairId()); + return body; + } + + @Override + public void updateRepairAndHandleIdByTempRepairId(String tempRepairId, String repairId, String handleId) { + LambdaUpdateWrapper qw = new LambdaUpdateWrapper<>(); + qw.eq(RepairFile::getRepairId, tempRepairId) + .set(RepairFile::getRepairId, repairId) + .set(RepairFile::getHandleId, handleId); + update(qw); + } + + @Override + public void updateHandleIdByTempHandleId(String tempHandleId, String handleId) { + LambdaUpdateWrapper qw = new LambdaUpdateWrapper<>(); + qw.eq(RepairFile::getHandleId, tempHandleId) + .set(RepairFile::getHandleId, handleId); + update(qw); + } + + @Override + public List listByRepairId(String repairId) { + LambdaQueryWrapper qw = new LambdaQueryWrapper<>(); + qw.eq(RepairFile::getRepairId, repairId) + .orderByAsc(RepairFile::getUploadTime); + return list(qw); + } + + @Override + public void downloadFile(String uuid, boolean online, HttpServletResponse response) throws IOException { + RepairFile repairFile = getById(uuid); + if (repairFile == null) { + return; + } + //拼接绝对路径,获取流 + InputStream is; + try { + is = new FileInputStream(devopsDir + "/" + repairFile.getFilePath()); + } catch (FileNotFoundException e) { + log.warn(e.getMessage()); + return; + } + OutputStream os = response.getOutputStream(); + String fileName = new String(repairFile.getFileName().getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1); + if (online) { + //直接展示 + response.setHeader("Content-Disposition", "inline; filename=\"" + fileName + "\""); + } else { + //设置:当浏览器收到这份资源的时候,以下载的方式提醒用户,而不是直接显示 + response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\""); + } + byte[] buffer = new byte[4096]; + int len; + while ((len = is.read(buffer)) != -1) { + os.write(buffer, 0, len); + } + os.close(); + is.close(); + } + + @Override + public void deleteFile(String uuid) { + RepairFile repairFile = getById(uuid); + if (repairFile == null) { + return; + } + File file = new File(devopsDir + "/" + repairFile.getFilePath()); + if (file.exists()) { + file.delete(); + } + removeById(repairFile); + } + + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/service/impl/RepairHandleServiceImpl.java b/src/main/java/com/chinaweal/youfool/devops/repair/service/impl/RepairHandleServiceImpl.java new file mode 100644 index 0000000..34587fa --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/service/impl/RepairHandleServiceImpl.java @@ -0,0 +1,99 @@ +package com.chinaweal.youfool.devops.repair.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.chinaweal.youfool.devops.repair.entity.RepairHandle; +import com.chinaweal.youfool.devops.repair.entity.RepairTodo; +import com.chinaweal.youfool.devops.repair.mapper.RepairHandleMapper; +import com.chinaweal.youfool.devops.repair.service.IRepairFileService; +import com.chinaweal.youfool.devops.repair.service.IRepairHandleService; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.chinaweal.youfool.devops.repair.service.IRepairTodoService; +import com.chinaweal.youfool.framework.springboot.rest.RestResult; +import com.chinaweal.youfool.framework.springboot.rest.ResultCode; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + *

+ * 运维报障处理流程记录 服务实现类 + *

+ * + * @author chinaweal + * @since 2020-06-05 + */ +@Service +public class RepairHandleServiceImpl extends ServiceImpl implements IRepairHandleService { + + @Resource + private RepairHandleMapper repairHandleMapper; + @Resource + private IRepairTodoService iRepairTodoService; + @Resource + private IRepairFileService iRepairFileService; + + @Override + public synchronized RepairHandle updateByRepairIdHandleTodo(RepairHandle repairHandle) { + LambdaUpdateWrapper qw = new LambdaUpdateWrapper<>(); + qw.eq(RepairHandle::getRepairId, repairHandle.getRepairId()).eq(RepairHandle::getStatus, "1") + .set(RepairHandle::getStatus, "0"); + + //失效以前的流程记录 + update(qw); + + //插入新的流程记录 + //todo 自动获取用户信息 + + repairHandle.setHandleId(null); + repairHandle.setHappenTime(LocalDateTime.now()); + repairHandle.setStatus("1"); + save(repairHandle); + + + return repairHandle; + } + + @Override + public List listByRepairId(String repairId) { + LambdaQueryWrapper qw = new LambdaQueryWrapper<>(); + qw.eq(RepairHandle::getRepairId, repairId).orderByAsc(RepairHandle::getHappenTime); + return list(qw); + } + + @Override + public RepairHandle getCurrentHandle(String repairId) { + LambdaQueryWrapper qw = new LambdaQueryWrapper<>(); + qw.eq(RepairHandle::getRepairId, repairId).eq(RepairHandle::getStatus, "1"); + return getOne(qw); + } + + @Override + public RestResult unresolvedHandle(RepairHandle repairHandle, String tempHandleId) { + //查询待办是否存在 + RepairTodo repairTodo = iRepairTodoService.getByRepairId(repairHandle.getRepairId()); + if (repairTodo == null) { + return RestResult.error(ResultCode.USCID_INVALID, "找不到对应的运维报障数据"); + } + + //插入流程表 + repairHandle.setTodoId(repairTodo.getTodoId()); + repairHandle.setStep(UNRESOLVED); + repairHandle = updateByRepairIdHandleTodo(repairHandle); + + //更改待办记录 + repairTodo.setHandleTime(repairHandle.getHappenTime()); + repairTodo.setStep(UNRESOLVED); + iRepairTodoService.updateById(repairTodo); + + //关联附件 + iRepairFileService.updateHandleIdByTempHandleId(tempHandleId, repairHandle.getHandleId()); + + return RestResult.ok(repairHandle.getHandleId()); + } + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/service/impl/RepairLabelServiceImpl.java b/src/main/java/com/chinaweal/youfool/devops/repair/service/impl/RepairLabelServiceImpl.java new file mode 100644 index 0000000..8bfeb77 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/service/impl/RepairLabelServiceImpl.java @@ -0,0 +1,64 @@ +package com.chinaweal.youfool.devops.repair.service.impl; + +import com.chinaweal.youfool.devops.base.entity.Dict; +import com.chinaweal.youfool.devops.base.service.IDictService; +import com.chinaweal.youfool.devops.repair.controller.query.RepairTodoListQuery; +import com.chinaweal.youfool.devops.repair.entity.RepairLabel; +import com.chinaweal.youfool.devops.repair.mapper.RepairLabelMapper; +import com.chinaweal.youfool.devops.repair.service.IRepairLabelService; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + *

+ * 运维单标签 服务实现类 + *

+ * + * @author chinaweal + * @since 2020-07-10 + */ +@Service +public class RepairLabelServiceImpl extends ServiceImpl implements IRepairLabelService { + + @Resource + private RepairLabelMapper repairLabelMapper; + @Resource + private IDictService iDictService; + + @Override + public List> listLabel() { + List> maps = repairLabelMapper.listLabelOrder(); + Map> labels = new LinkedHashMap<>(); + for (Map map : maps) { + String name = map.get("name"); + Map labelMap = new LinkedHashMap<>(); + labelMap.put("name", name); + labelMap.put("value", name); + labels.put(name, labelMap); + } + //查询基础数据去重并,合并起来 + List dicts = iDictService.listByType(IDictService.LABEL); + for (Dict dict : dicts) { + boolean b = labels.containsKey(dict.getCode()); + if (!b) { + Map labelMap = new LinkedHashMap<>(); + labelMap.put("name", dict.getName()); + labelMap.put("value", dict.getCode()); + labels.put(dict.getCode(), labelMap); + } + } + return new ArrayList<>(labels.values()); + } + + @Override + public List> groupLabelCount(RepairTodoListQuery query) { + List> labels = repairLabelMapper.groupNameCount(query); + return labels; + } +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/service/impl/RepairServiceImpl.java b/src/main/java/com/chinaweal/youfool/devops/repair/service/impl/RepairServiceImpl.java new file mode 100644 index 0000000..55da53c --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/service/impl/RepairServiceImpl.java @@ -0,0 +1,483 @@ +package com.chinaweal.youfool.devops.repair.service.impl; + +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.enums.WriteDirectionEnum; +import com.alibaba.excel.write.metadata.WriteSheet; +import com.alibaba.excel.write.metadata.fill.FillConfig; +import com.alibaba.excel.write.metadata.fill.FillWrapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.chinaweal.youfool.devops.base.service.IDictService; +import com.chinaweal.youfool.devops.org.business.entity.BusinessUser; +import com.chinaweal.youfool.devops.org.business.service.BusinessUserService; +import com.chinaweal.youfool.devops.repair.controller.query.RepairTodoListQuery; +import com.chinaweal.youfool.devops.repair.entity.*; +import com.chinaweal.youfool.devops.repair.mapper.RepairHandleMapper; +import com.chinaweal.youfool.devops.repair.mapper.RepairLabelMapper; +import com.chinaweal.youfool.devops.repair.mapper.RepairMapper; +import com.chinaweal.youfool.devops.repair.mapper.RepairTodoMapper; +import com.chinaweal.youfool.devops.repair.service.*; +import com.chinaweal.youfool.framework.springboot.rest.RestResult; +import com.chinaweal.youfool.framework.springboot.rest.ResultCode; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.util.Strings; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.OutputStream; +import java.math.BigDecimal; +import java.nio.charset.StandardCharsets; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.stream.Collectors; + +/** + *

+ * 运维报障信息 服务实现类 + *

+ * + * @author chinaweal + * @since 2020-06-05 + */ +@Service +@Slf4j +public class RepairServiceImpl extends ServiceImpl implements IRepairService { + + @Resource + private IDictService iDictService; + @Resource + private IRepairHandleService iRepairHandleService; + @Resource + private IRepairFileService iRepairFileService; + @Resource + private IRepairTodoService iRepairTodoService; + @Resource + private RepairTodoMapper repairTodoMapper; + @Resource + private RepairHandleMapper repairHandleMapper; + @Resource + private RepairLabelMapper repairLabelMapper; + @Resource + private IRepairLabelService iRepairLabelService; + @Resource + private BusinessUserService businessUserService; + + @Override + public RestResult saveRepair(Repair repair) { + + //判断来源 + if ("2".equals(repair.getSource())) { + repair.setOrgId("特设网办系统"); + repair.setOrg("特设网办系统"); + } else if ("3".equals(repair.getSource())) { + repair.setOrgId("佛山年报系统"); + repair.setOrg("佛山年报系统"); + } else if ("4".equals(repair.getSource())) { + repair.setOrgId("佛山行政执法办案平台"); + repair.setOrg("佛山行政执法办案平台"); + } else if ("5".equals(repair.getSource())) { + repair.setOrgId("佛山消保系统"); + repair.setOrg("佛山消保系统"); + } else { + //内网发起,查询业务系统的用户信息 + BusinessUser user; + if (StringUtils.isNotBlank(repair.getUserId())) { + user = businessUserService.getById(repair.getUserId()); + } else { + user = businessUserService.getByUsername(repair.getUsername()); + } + if (user == null) { + return RestResult.error(ResultCode.USCID_INVALID, "找不到申报账号信息"); + } + repair.setUserId(user.getUserId()); + repair.setUsername(user.getUsername()); + repair.setDeptId(user.getUnitId()); + repair.setDept(user.getUnitName()); + repair.setOrgId(user.getOrgId()); + repair.setOrg(user.getOrgName()); + repair.setNickname(user.getNickname()); + if (StringUtils.isBlank(repair.getPhone())) { + repair.setPhone(user.getMobile()); + } + repair.setSource("1");//内网 + } + + String oldRepairUUID = repair.getRepairId(); + String repairId = generateRepairId(); + repair.setRepairId(repairId); + repair.setLaunchTime(LocalDateTime.now()); + save(repair); + + + //生成待办 + RepairTodo repairTodo = iRepairTodoService.generateTodo(repair); + //初始化流程记录 + RepairHandle repairHandle = new RepairHandle(repairTodo.getTodoId(), repairTodo.getRepairId(), repairTodo.getStep(), + repair.getUsername(), repair.getNickname(), null); + repairHandle = iRepairHandleService.updateByRepairIdHandleTodo(repairHandle); + + //判断是否有附件上传的工单,更新附件的运维ID + if (StringUtils.isNotBlank(oldRepairUUID)) { + iRepairFileService.updateRepairAndHandleIdByTempRepairId(oldRepairUUID, repair.getRepairId(), repairHandle.getHandleId()); + } + + //判断标签是否已经入库了,否则重新入库 + if (StringUtils.isNotBlank(repair.getBusClassify())) { + iDictService.saveNameByTypeCode("busClassify", repair.getBusClassify(), repair.getBusClassify()); + } + if (StringUtils.isNotBlank(repair.getBusStep())) { + iDictService.saveNameByTypeCode("busStep", repair.getBusStep(), repair.getBusStep()); + } + + return RestResult.ok(repair.getRepairId()); + } + + private synchronized String generateRepairId() { + String prefix = "YW" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); + //查询当天有多少条工单 + LambdaQueryWrapper qw = new LambdaQueryWrapper<>(); + qw.ge(Repair::getLaunchTime, LocalDate.now().atStartOfDay()) + .lt(Repair::getLaunchTime, LocalDate.now().atStartOfDay().plusDays(1)); + int count = count(qw) + 1; + //补齐零 + String no = String.format("%04d", count); + String repairId = prefix + no; + Repair repair = getById(repairId); + //效验运维单号的序号唯一不 + int max = 10; + while (repair != null && max != 0) { + log.warn("效验运维单号的序号有重复的,请注意检查数据!重复单号:{}", repairId); + count++; + max--; + no = String.format("%04d", count); + repairId = prefix + no; + repair = getById(repairId); + } + + return repairId; + } + + @Override + public RestResult updateRepair(Repair repair) { + + updateById(repair); + iRepairTodoService.updateTodo(repair); + //判断标签是否已经入库了,否则重新入库 + if (StringUtils.isNotBlank(repair.getBusClassify())) { + iDictService.saveNameByTypeCode("busClassify", repair.getBusClassify(), repair.getBusClassify()); + } + if (StringUtils.isNotBlank(repair.getBusStep())) { + iDictService.saveNameByTypeCode("busStep", repair.getBusStep(), repair.getBusStep()); + } + + return RestResult.ok(repair.getRepairId()); + } + + @Override + public Repair getRepair(String repairId) { + + Repair repair = getById(repairId); + + //文件列表 + List listFile = iRepairFileService.listByRepairId(repair.getRepairId()); + + repair.setQuestionFiles(listFile.stream().filter(item -> "question".equals(item.getType())).collect(Collectors.toList())); + repair.setAnswerFiles(listFile.stream().filter(item -> "answer".equals(item.getType())).collect(Collectors.toList())); + + //流程记录 + List listRepairHandle = iRepairHandleService.listByRepairId(repair.getRepairId()); + //获取流程记录的附件列表 + for (RepairHandle repairHandle : listRepairHandle) { + LambdaQueryWrapper rfQw = new LambdaQueryWrapper<>(); + rfQw.eq(RepairFile::getHandleId, repairHandle.getHandleId()); + List files = iRepairFileService.list(rfQw); + repairHandle.setFiles(files); + } + repair.setRepairHandles(listRepairHandle); + + //获取当前状态流程 + RepairHandle currentHandle = iRepairHandleService.getCurrentHandle(repair.getRepairId()); + LambdaQueryWrapper rfQw = new LambdaQueryWrapper<>(); + rfQw.eq(RepairFile::getHandleId, currentHandle.getHandleId()); + List files = iRepairFileService.list(rfQw); + currentHandle.setFiles(files); + + repair.setCurrentHandle(currentHandle); + + //查询待办信息 + RepairTodo repairTodo = iRepairTodoService.getByRepairId(repairId); + repair.setRepairTodo(repairTodo); + + //查询标签 + List labels = repairLabelMapper.listNameByRepairId(repairId); + repair.setLabels(labels); + return repair; + } + + @Override + public void updateLabelByType(List repairIds, String labelType, String labelName) { + //判断标签是否入库字典表了,否则新入库 + iDictService.saveNameByTypeCode(labelType, labelName, labelName); + LambdaUpdateWrapper rqw = new LambdaUpdateWrapper<>(); + rqw.in(Repair::getRepairId, repairIds); + if ("busClassify".equals(labelType)) { + rqw.set(Repair::getBusClassify, labelName); + } else if ("busStep".equals(labelType)) { + rqw.set(Repair::getBusStep, labelName); + } else { + return; + } + update(rqw); + } + + @Override + public List> sumSummary(RepairTodoListQuery query) { + List> list = new LinkedList<>(); + BigDecimal total = repairHandleMapper.countStep(query, "total"); + BigDecimal resolved = repairHandleMapper.countStep(query, "resolved"); + BigDecimal untreated = repairHandleMapper.countStep(query, "untreated"); + BigDecimal confirmed = repairHandleMapper.countStep(query, "confirmed"); + + //报障总数量 + Map totalData = new LinkedHashMap<>(); + totalData.put("id", "total"); + totalData.put("name", "报障总数"); + totalData.put("value", total); + + //已处理报障数量(已解决) + Map feedbackData = new LinkedHashMap<>(); + feedbackData.put("id", "resolved"); + feedbackData.put("name", "已归档"); + feedbackData.put("value", resolved); + + + //未处理报障数量 + Map untreatedData = new LinkedHashMap<>(); + untreatedData.put("id", "untreated"); + untreatedData.put("name", "未处理"); + untreatedData.put("value", untreated); + + + //待报障单位确认的报障数量 + Map confirmedData = new LinkedHashMap<>(); + confirmedData.put("id", "confirmed"); + confirmedData.put("name", "已处理待确认"); + confirmedData.put("value", confirmed); + + + //故障处理率 + Map processRaterDate = new LinkedHashMap<>(); + processRaterDate.put("id", "processRate"); + processRaterDate.put("name", "故障处理率(已确认)"); + processRaterDate.put("value", total.compareTo(BigDecimal.valueOf(0)) > 0 ? (resolved.multiply(BigDecimal.valueOf(100)) + .divide(total, 2, BigDecimal.ROUND_HALF_UP) + "%") : 0); + + + //已解决+待确认 故障处理率 + Map confirmedProcessRaterDate = new LinkedHashMap<>(); + confirmedProcessRaterDate.put("id", "confirmedProcessRate"); + confirmedProcessRaterDate.put("name", "故障处理率(已确认+待确认)"); + confirmedProcessRaterDate.put("value", total.compareTo(BigDecimal.valueOf(0)) > 0 ? (resolved.add(confirmed).multiply(BigDecimal.valueOf(100)) + .divide(total, 2, BigDecimal.ROUND_HALF_UP) + "%") : 0); + + + //处理故障数量 + BigDecimal oneSuccess = repairHandleMapper.countResultSecond(query, 1); + BigDecimal twoSuccess = repairHandleMapper.countResultSecond(query, 2); + BigDecimal threeSuccess = repairHandleMapper.countResultSecond(query, 3); + BigDecimal handleTotal = oneSuccess.add(twoSuccess).add(threeSuccess); + + Map one = new LinkedHashMap<>(); + one.put("id", "oneSuccess"); + one.put("name", "处理故障1次成功数量"); + one.put("value", oneSuccess); + + Map oneRate = new LinkedHashMap<>(); + oneRate.put("id", "oneSuccessRate"); + oneRate.put("name", "处理故障1次成功率"); + oneRate.put("value", handleTotal.compareTo(BigDecimal.valueOf(0)) > 0 ? (oneSuccess.multiply(BigDecimal.valueOf(100)) + .divide(handleTotal, 2, BigDecimal.ROUND_HALF_UP) + "%") : 0); + + + Map two = new LinkedHashMap<>(); + two.put("id", "twoSuccess"); + two.put("name", "处理故障2次成功数量"); + two.put("value", twoSuccess); + + Map twoRate = new LinkedHashMap<>(); + twoRate.put("id", "twoSuccessRate"); + twoRate.put("name", "处理故障2次成功率"); + twoRate.put("value", handleTotal.compareTo(BigDecimal.valueOf(0)) > 0 ? (twoSuccess.multiply(BigDecimal.valueOf(100)) + .divide(handleTotal, 2, BigDecimal.ROUND_HALF_UP) + "%") : 0); + + + Map three = new LinkedHashMap<>(); + three.put("id", "threeSuccess"); + three.put("name", "处理故障3次及以上成功数量"); + three.put("value", threeSuccess); + + Map threeRate = new LinkedHashMap<>(); + threeRate.put("id", "threeSuccessRate"); + threeRate.put("name", "处理故障3次及以上成功率"); + threeRate.put("value", handleTotal.compareTo(BigDecimal.valueOf(0)) > 0 ? (threeSuccess.multiply(BigDecimal.valueOf(100)) + .divide(handleTotal, 2, BigDecimal.ROUND_HALF_UP) + "%") : 0); + + Map avgResolvedMap = repairHandleMapper.getAvgResolvedTime(query); + Map avgResolvedTime = new LinkedHashMap<>(); + BigDecimal resolvedHour = (BigDecimal) avgResolvedMap.get("resolvedHour"); + BigDecimal resolvedNumber = (BigDecimal) avgResolvedMap.get("resolvedNumber"); + avgResolvedTime.put("id", "avgResolvedTime"); + avgResolvedTime.put("name", "故障平均解决时长"); + avgResolvedTime.put("value", resolvedNumber.compareTo(BigDecimal.valueOf(0)) > 0 ? (resolvedHour.divide(resolvedNumber, 2, BigDecimal.ROUND_HALF_UP)) + " 小时" : 0); + + Map avgFeedbackMap = repairHandleMapper.getAvgFeedbackTime(query); + Map avgFeedbackTime = new LinkedHashMap<>(); + BigDecimal feedbackHour = (BigDecimal) avgFeedbackMap.get("feedbackHour"); + BigDecimal feedbackNumber = (BigDecimal) avgFeedbackMap.get("feedbackNumber"); + avgFeedbackTime.put("id", "avgFeedbackTime"); + avgFeedbackTime.put("name", "故障平均处理时长"); + avgFeedbackTime.put("value", feedbackNumber.compareTo(BigDecimal.valueOf(0)) > 0 ? (feedbackHour.divide(feedbackNumber, 2, BigDecimal.ROUND_HALF_UP)) + " 小时" : 0); + + list.add(totalData); + list.add(feedbackData); + list.add(untreatedData); + list.add(confirmedData); + list.add(one); + list.add(two); + list.add(three); + + list.add(avgFeedbackTime); + list.add(avgResolvedTime); + + list.add(processRaterDate); + list.add(confirmedProcessRaterDate); + list.add(oneRate); + list.add(twoRate); + list.add(threeRate); + return list; + } + + @Override + public List> sumBusLabelByType(RepairTodoListQuery query, String labelType) { + List> list = new LinkedList<>(); + List> labelList = null; + if ("labelBusClassify".equals(labelType)) { + labelList = repairTodoMapper.groupByBusClassifyCount(query); + } else if ("labelBusStep".equals(labelType)) { + labelList = repairTodoMapper.groupByBusStepCount(query); + } + for (Map map : labelList) { + String name = (String) map.get("name"); + BigDecimal num = (BigDecimal) map.get("num"); + Map data = new LinkedHashMap<>(); + data.put("id", labelType + name); + data.put("name", name); + data.put("value", num); + list.add(data); + } + return list; + } + + + @Override + public void exportSumSummary(RepairTodoListQuery query, HttpServletResponse response) throws IOException { + String fileName = new String(("报障统计汇总.xlsx").getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1); + //response为HttpServletResponse对象 + response.setContentType("application/vnd.ms-excel;charset=utf-8"); + response.setHeader("Content-Disposition", "attachment; filename=" + fileName); + OutputStream os = response.getOutputStream(); + + String templateFileName = this.getClass().getResource("/excel/tongjineirongxiang.xlsx").getPath(); + ExcelWriter excelWriter = EasyExcel.write(os).withTemplate(templateFileName).build(); + WriteSheet writeSheet = EasyExcel.writerSheet().build(); + FillConfig fillConfig = FillConfig.builder().direction(WriteDirectionEnum.HORIZONTAL).build(); + + excelWriter.fill(sumSummary(query), fillConfig, writeSheet); + + Map map = new HashMap<>(); + //处理时间 + if (query.getLaunchTimeStart() != null) { + String start = query.getLaunchTimeStart().format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")); + String end = query.getLaunchTimeEnd().format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")); + map.put("date", start + " 至 " + end); + } else { + map.put("date", "全部"); + } + if (query.getOrgListLike() != null && !query.getOrgListLike().isEmpty()) { + map.put("org", Strings.join(query.getOrgListLike(), '、')); + } else { + map.put("org", "全市"); + } + + List> labelBusClassify = sumBusLabelByType(query, "labelBusClassify"); + excelWriter.fill(new FillWrapper("labelBusClassify", labelBusClassify), fillConfig, writeSheet); + List> labelBusStep = sumBusLabelByType(query, "labelBusStep"); + excelWriter.fill(new FillWrapper("labelBusStep", labelBusStep), fillConfig, writeSheet); + + excelWriter.fill(map, writeSheet); + excelWriter.finish(); + } + + @Override + public void updateDevInfo(Map map) { + String repairId = (String) map.get("repairId"); + String leaderUsername = (String) map.get("leaderUsername"); + String leaderNickname = (String) map.get("leaderNickname"); + String questionType = (String) map.get("questionType"); + Integer priority = (Integer) map.get("priority"); + String thinking = (String) map.get("thinking"); + String plannedTimeStr = (String) map.get("plannedTime"); + String realityTimeStr = (String) map.get("realityTime"); + List labels = (List) map.get("labels"); + + Repair repair = getRepair(repairId); + + if (StringUtils.isNotBlank(plannedTimeStr)) { + LocalDateTime plannedTime = LocalDateTime.parse(plannedTimeStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + repair.setPlannedTime(plannedTime); + } + if (StringUtils.isNotBlank(realityTimeStr)) { + LocalDateTime realityTime = LocalDateTime.parse(realityTimeStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + repair.setRealityTime(realityTime); + } + if (repair == null) { + return; + } + repair.setLeaderUsername(leaderUsername); + repair.setLeaderNickname(leaderNickname); + repair.setQuestionType(questionType); + repair.setPriority(priority); + repair.setThinking(thinking); + //标签字符全量插入 + if (labels != null) { + repair.setLabel(String.join(",", labels)); + } + updateById(repair); + + //待办列表 + RepairTodo repairTodo = iRepairTodoService.getByRepairId(repairId); + repairTodo.setPriority(priority); + iRepairTodoService.updateById(repairTodo); + + //删除旧的标签 + LambdaQueryWrapper qw = new LambdaQueryWrapper<>(); + qw.eq(RepairLabel::getRepairId, repair.getRepairId()); + iRepairLabelService.remove(qw); + //全量问题标签全量插入 + if (labels != null) { + for (String label : labels) { + RepairLabel repairLabel = new RepairLabel(); + repairLabel.setName(label); + repairLabel.setRepairId(repair.getRepairId()); + iRepairLabelService.save(repairLabel); + } + } + } +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/service/impl/RepairSummaryServiceImpl.java b/src/main/java/com/chinaweal/youfool/devops/repair/service/impl/RepairSummaryServiceImpl.java new file mode 100644 index 0000000..0b01ff4 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/service/impl/RepairSummaryServiceImpl.java @@ -0,0 +1,111 @@ +package com.chinaweal.youfool.devops.repair.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.chinaweal.youfool.devops.base.entity.Dict; +import com.chinaweal.youfool.devops.base.service.IDictService; +import com.chinaweal.youfool.devops.repair.controller.query.RepairTodoListQuery; +import com.chinaweal.youfool.devops.repair.entity.RepairSummary; +import com.chinaweal.youfool.devops.repair.entity.RepairTodo; +import com.chinaweal.youfool.devops.repair.mapper.RepairHandleMapper; +import com.chinaweal.youfool.devops.repair.mapper.RepairMapper; +import com.chinaweal.youfool.devops.repair.mapper.RepairSummaryMapper; +import com.chinaweal.youfool.devops.repair.mapper.RepairTodoMapper; +import com.chinaweal.youfool.devops.repair.service.IRepairSummaryService; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.chinaweal.youfool.devops.repair.service.IRepairTodoService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; + +import static com.chinaweal.youfool.devops.repair.service.IRepairHandleService.FEEDBACK; + +/** + *

+ * 运维报障统计汇总 服务实现类 + *

+ * + * @author chinaweal + * @since 2020-08-13 + */ +@Service +public class RepairSummaryServiceImpl extends ServiceImpl implements IRepairSummaryService { + @Resource + private RepairTodoMapper repairTodoMapper; + + @Resource + private RepairHandleMapper repairHandleMapper; + @Resource + private RepairMapper repairMapper; + @Resource + private IDictService iDictService; + + @Override + public void sumAllOrgByDay(LocalDate day) { + List list = new ArrayList<>(); + LocalDateTime startTime = day.atStartOfDay(); + LocalDateTime endTime = startTime.plusDays(1).minusSeconds(1); + for (String orgName : IRepairSummaryService.getOrgNameList()) { + + //报障数 + Long reportTotal = repairTodoMapper.countByLaunchTimeAndLikeOrg(startTime, endTime, Collections.singletonList(orgName)); + + //业务数 todo + + //处理数 + Long handleTotal = repairHandleMapper.countDistinctByTimeAndOrgAndStep(startTime, endTime, Collections.singletonList(orgName), FEEDBACK); + + RepairSummary repairSummary = new RepairSummary(); + repairSummary.setOrg(orgName); + repairSummary.setType(ORG); + repairSummary.setTime(startTime); + repairSummary.setReportTotal(BigDecimal.valueOf(reportTotal)); + repairSummary.setHandleTotal(BigDecimal.valueOf(handleTotal)); + repairSummary.setBusTotal(BigDecimal.valueOf(0));// TODO: 2020/8/14 + + list.add(repairSummary); + } + saveBatch(list); + } + + @Override + public void sumAllOrgAndGroupQuestionByDay(LocalDate day) { + List list = new ArrayList<>(); + LocalDateTime startTime = day.atStartOfDay(); + LocalDateTime endTime = startTime.plusDays(1).minusSeconds(1); + //获取问题分类基础数据 + List dicts = iDictService.listByType(IDictService.QUESTION); + List questions = dicts.stream().map(Dict::getName).collect(Collectors.toList()); + + for (String orgName : IRepairSummaryService.getOrgNameList()) { + //分组问题分类 的报障数 + RepairTodoListQuery query = new RepairTodoListQuery(); + query.setOrgListLike(Collections.singletonList(orgName)); + query.setLaunchTimeStart(startTime); + query.setLaunchTimeEnd(endTime); + //遍历问题分类 + for (String question : questions) { + query.setQuestionType(question); + BigDecimal number = repairMapper.countByQuestionType(query); + RepairSummary repairSummary = new RepairSummary(); + repairSummary.setOrg(orgName); + repairSummary.setType(ORG_QUESTION); + repairSummary.setTime(startTime); + repairSummary.setReportTotal(number); + repairSummary.setQuestionType(question); + list.add(repairSummary); + } + } + //删除旧的历史记录 + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.ge(RepairSummary::getTime, startTime).le(RepairSummary::getTime, endTime); + lqw.eq(RepairSummary::getType, ORG_QUESTION); + remove(lqw); + + saveBatch(list); + } +} diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/service/impl/RepairTodoServiceImpl.java b/src/main/java/com/chinaweal/youfool/devops/repair/service/impl/RepairTodoServiceImpl.java new file mode 100644 index 0000000..6ac3cb8 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/service/impl/RepairTodoServiceImpl.java @@ -0,0 +1,717 @@ +package com.chinaweal.youfool.devops.repair.service.impl; + +import com.alibaba.excel.EasyExcel; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.metadata.OrderItem; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.chinaweal.youfool.devops.org.business.service.BusinessUserService; +import com.chinaweal.youfool.devops.org.entity.Engineer; +import com.chinaweal.youfool.devops.org.service.IEngineerService; +import com.chinaweal.youfool.devops.repair.controller.query.RepairTodoListQuery; +import com.chinaweal.youfool.devops.repair.entity.Repair; +import com.chinaweal.youfool.devops.repair.entity.RepairHandle; +import com.chinaweal.youfool.devops.repair.entity.RepairLabel; +import com.chinaweal.youfool.devops.repair.entity.RepairTodo; +import com.chinaweal.youfool.devops.repair.excel.CustomRowCellWriteHandler; +import com.chinaweal.youfool.devops.repair.excel.LocalDateTimeConverter; +import com.chinaweal.youfool.devops.repair.excel.RepairTodoExcel; +import com.chinaweal.youfool.devops.repair.mapper.RepairHandleMapper; +import com.chinaweal.youfool.devops.repair.mapper.RepairTodoMapper; +import com.chinaweal.youfool.devops.repair.service.*; +import com.chinaweal.youfool.devops.websocket.server.BusinessSysServer; +import com.chinaweal.youfool.framework.springboot.rest.RestResult; +import com.chinaweal.youfool.framework.springboot.rest.ResultCode; +import com.chinaweal.youfool.framework.springboot.user.entity.UserBase; +import com.chinaweal.youfool.framework.springboot.user.service.UserBaseService; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.OutputStream; +import java.lang.reflect.Method; +import java.math.BigDecimal; +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; + +/** + *

+ * 运维报障待办 服务实现类 + *

+ * + * @author chinaweal + * @since 2020-06-05 + */ +@Service +public class RepairTodoServiceImpl extends ServiceImpl implements IRepairTodoService { + @Resource + private RepairTodoMapper repairTodoMapper; + @Resource + private IRepairHandleService iRepairHandleService; + @Resource + private RepairHandleMapper repairHandleMapper; + @Resource + private IRepairFileService iRepairFileService; + @Resource + private IRepairService iRepairService; + @Resource + private BusinessUserService businessUserService; + @Resource + private IEngineerService iEngineerService; + @Resource + private IRepairLabelService iRepairLabelService; + + + @Override + public RepairTodo getByRepairId(String repairId) { + LambdaQueryWrapper qw = new LambdaQueryWrapper<>(); + qw.eq(RepairTodo::getRepairId, repairId); + return getOne(qw); + } + + private Page setPage(RepairTodoListQuery query) { + String[] repairField = {"question_type", "leader_nickname", "bus_classify", "bus_step"}; + Page page = new Page<>(query.getCurrent(), query.getSize()); + if (StringUtils.isNotBlank(query.getOrderField())) { + if ("desc".equalsIgnoreCase(query.getOrderSort())) { + //详细表的字段排序 + if (ArrayUtils.contains(repairField, query.getOrderField())) { + page.addOrder(OrderItem.desc("r." + query.getOrderField())); + } else { + page.addOrder(OrderItem.desc("rt." + query.getOrderField())); + } + } else { + //详细表的字段排序 + if (ArrayUtils.contains(repairField, query.getOrderField())) { + page.addOrder(OrderItem.asc("r." + query.getOrderField())); + } else { + page.addOrder(OrderItem.asc("rt." + query.getOrderField())); + } + } + } else { + page.addOrder(OrderItem.asc("rt.launch_time")); + } + return page; + } + + @Override + public IPage findList(RepairTodoListQuery query) { + Page page = setPage(query); + return repairTodoMapper.listTodo(page, query); + } + + @Override + public RepairTodo generateTodo(Repair repair) { + RepairTodo repairTodo = new RepairTodo(); + BeanUtils.copyProperties(repair, repairTodo); + repairTodo.setSource(repair.getSource()); + repairTodo.setDeleted("0"); + repairTodo.setStep(IRepairHandleService.DECLARE); + + save(repairTodo); + return repairTodo; + } + + @Override + public RepairTodo updateTodo(Repair repair) { + RepairTodo repairTodo = getByRepairId(repair.getRepairId()); + BeanUtils.copyProperties(repair, repairTodo); + updateById(repairTodo); + return repairTodo; + + } + + @Override + public void exportTodo(RepairTodoListQuery query, HttpServletResponse response, String type) throws IOException { + + Page page = setPage(query).setCurrent(0).setSize(10000000000000000L); + + IPage todoIPage; + if (query.getTodoIds() != null && query.getTodoIds().length > 0) { + todoIPage = repairTodoMapper.listByTodoId(page, query.getTodoIds()); + } else { + todoIPage = repairTodoMapper.listTodo(page, query); + } + List list = new ArrayList<>(); + List records = todoIPage.getRecords(); + int i = 0; + for (RepairTodo repairTodo : records) { + RepairTodoExcel repairTodoExcel = new RepairTodoExcel(); + BeanUtils.copyProperties(repairTodo, repairTodoExcel); + repairTodoExcel.setNo(++i); + list.add(repairTodoExcel); + } + //找出最大的时间 + LocalDateTime launchTimeMax = records.stream().max((o1, o2) -> { + boolean after = o1.getLaunchTime().isBefore(o2.getLaunchTime()); + return after ? 0 : 1; + }).map(RepairTodo::getLaunchTime).orElse(null); + LocalDateTime launchTimeMin = records.stream().min((o1, o2) -> { + boolean before = o1.getLaunchTime().isAfter(o2.getLaunchTime()); + return before ? 1 : 0; + }).map(RepairTodo::getLaunchTime).orElse(null); + + String date = ""; + if (launchTimeMin != null) { + date = launchTimeMin.toLocalDate().toString(); + } + if (launchTimeMax != null) { + String maxDate = launchTimeMax.toLocalDate().toString(); + if (!date.equals(maxDate)) { + date += " - " + maxDate; + } + } + + String fileName = new String(("运维报障系统" + date + "报障记录.xlsx").getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1); + //response为HttpServletResponse对象 + response.setContentType("application/vnd.ms-excel;charset=utf-8"); + response.setHeader("Content-Disposition", "attachment; filename=" + fileName); + + OutputStream os = response.getOutputStream(); + + //根据字段列表,导出那些表头字段 + String[] fields = query.getFields(); + List exportFields = new ArrayList<>(); + List> titles = new ArrayList<>(); + Map fieldsMap; + if ("dev".equals(type)) { + fieldsMap = excelDevFields(); + } else { + fieldsMap = excelBusinessFields(); + } + List fieldName = new ArrayList<>(); + //大标题 + fieldName.add("运维报障系统 " + date + " 报障记录"); + //序号 + fieldName.add("序号"); + titles.add(fieldName); + //生成表头 + if (fields != null && fields.length > 0) { + for (String fieldId : fieldsMap.keySet()) { + boolean contains = ArrayUtils.contains(fields, fieldId); + if (contains) { + fieldName = new ArrayList<>(); + fieldName.add(fieldsMap.get(fieldId)); + titles.add(fieldName); + exportFields.add(fieldId); + } + } + } else { + //默认导出所有表头 + for (String value : fieldsMap.values()) { + fieldName = new ArrayList<>(); + fieldName.add(value); + titles.add(fieldName); + } + exportFields.addAll(fieldsMap.keySet()); + } + + List> data = new ArrayList<>(); + try { + for (RepairTodoExcel repairTodoExcel : list) { + Class aClass = repairTodoExcel.getClass(); + List item = new ArrayList<>(); + item.add(repairTodoExcel.getNo()); + for (String field : exportFields) { + Method method = aClass.getMethod(field); + Object value = method.invoke(repairTodoExcel); + item.add(value); + } + data.add(item); + } + } catch (Exception e) { + log.error(e.getMessage(), e); + } + EasyExcel.write(os).head(titles).useDefaultStyle(false).automaticMergeHead(false) + .registerWriteHandler(new CustomRowCellWriteHandler()) + .registerConverter(new LocalDateTimeConverter()) + .sheet(date + "报障清单").doWrite(data); + + os.close(); + } + + @Override + public RestResult assign(RepairHandle repairHandle) { + //查询待办是否存在 + RepairTodo repairTodo = getByRepairId(repairHandle.getRepairId()); + if (repairTodo == null) { + return RestResult.error(ResultCode.USCID_INVALID, "找不到对应的运维报障数据"); + } + //插入流程表 + repairHandle.setTodoId(repairTodo.getTodoId()); + repairHandle = iRepairHandleService.updateByRepairIdHandleTodo(repairHandle); + + //更改待办分派人员记录 + repairTodo.setHandleTime(repairHandle.getHappenTime()); + repairTodo.setStep(repairHandle.getStep()); + repairTodo.setPriority(repairHandle.getPriority()); + updateById(repairTodo); + + Repair repair = new Repair(); + repair.setRepairId(repairHandle.getRepairId()); + repair.setPriority(repairHandle.getPriority()); + repair.setQuestionType(repairHandle.getQuestionType()); + repair.setPlannedTime(repairHandle.getPlannedTime()); + repair.setLeaderNickname(repairHandle.getLeaderNickname()); + repair.setLeaderUsername(repairHandle.getLeaderUsername()); + repair.setThinking(repairHandle.getThinking()); + //标签字符全量插入 + if (repairHandle.getLabels() != null) { + repair.setLabel(String.join(",", repairHandle.getLabels())); + } + + iRepairService.updateById(repair); + + //因为分派,自动生成处理中这个环节记录 + //等待300毫秒区分排序 + try { + Thread.sleep(300); + } catch (InterruptedException e) { + e.printStackTrace(); + } + RepairHandle acceptHandle = new RepairHandle(repairTodo.getTodoId(), repairTodo.getRepairId(), IRepairHandleService.HANDLE, + repairHandle.getNextHandleUsername(), repairHandle.getNextHandleNickname(), null); + acceptHandle = iRepairHandleService.updateByRepairIdHandleTodo(acceptHandle); + + //更改待办 + repairTodo.setHandleTime(acceptHandle.getHappenTime()); + repairTodo.setEngineer(acceptHandle.getHandleNickname()); + repairTodo.setEngineerUsername(acceptHandle.getHandleUsername()); + repairTodo.setStep(acceptHandle.getStep()); + updateById(repairTodo); + + //删除旧的标签 + LambdaQueryWrapper qw = new LambdaQueryWrapper<>(); + qw.eq(RepairLabel::getRepairId, repair.getRepairId()); + iRepairLabelService.remove(qw); + //全量标签全量插入 + if (repairHandle.getLabels() != null) { + for (String labelStr : repairHandle.getLabels()) { + RepairLabel label = new RepairLabel(); + label.setName(labelStr); + label.setRepairId(repair.getRepairId()); + iRepairLabelService.save(label); + } + } + + return RestResult.ok(repairHandle.getHandleId()); + } + + @Override + public RestResult generateNextHandle(RepairHandle repairHandle) { + //查询待办是否存在 + RepairTodo repairTodo = getByRepairId(repairHandle.getRepairId()); + if (repairTodo == null) { + return RestResult.error(ResultCode.USCID_INVALID, "找不到对应的运维报障数据"); + } + //插入流程表 + repairHandle.setTodoId(repairTodo.getTodoId()); + repairHandle = iRepairHandleService.updateByRepairIdHandleTodo(repairHandle); + + //更改待办记录 + repairTodo.setHandleTime(repairHandle.getHappenTime()); + repairTodo.setStep(repairHandle.getStep()); + updateById(repairTodo); + + return RestResult.ok(repairHandle.getHandleId()); + } + + @Override + public Map countRepairStepByUserId(String userId) { + QueryWrapper qw = new QueryWrapper<>(); + qw.select("STEP AS STEP,COUNT(*) AS NUM") + .eq("USER_ID", userId) + .groupBy("STEP").orderByDesc("NUM"); + + List> list = listMaps(qw); + Map body = new LinkedHashMap<>(); + for (Map map : list) { + Object step = map.get("STEP"); + if (step == null) { + continue; + } + body.put(map.get("STEP").toString().toLowerCase(), ((BigDecimal) map.get("NUM")).intValue()); + } + return body; + } + + @Override + public RestResult feedback(RepairHandle repairHandle, String tempHandleId) { + String[] labels = repairHandle.getLabels(); + RepairHandle loadRepairHandle = iRepairHandleService.getById(repairHandle.getHandleId()); + if (loadRepairHandle == null || !"1".equals(loadRepairHandle.getStatus())) { + return RestResult.error(ResultCode.USCID_INVALID, "当前处理记录无效"); + } + //查询待办是否存在 + RepairTodo repairTodo = getByRepairId(repairHandle.getRepairId()); + if (repairTodo == null) { + return RestResult.error(ResultCode.USCID_INVALID, "找不到对应的运维报障数据"); + } + //更新处理结果 + loadRepairHandle.setResult(repairHandle.getResult()); + loadRepairHandle.setHandleUsername(repairHandle.getHandleUsername()); + loadRepairHandle.setHandleNickname(repairHandle.getHandleNickname()); + loadRepairHandle.setHappenTime(LocalDateTime.now()); + //上一步是处理中则修改,或者还是处于处理反馈环节 + if (IRepairHandleService.HANDLE.equals(loadRepairHandle.getStep()) + || IRepairHandleService.FEEDBACK.equals(loadRepairHandle.getStep())) { + loadRepairHandle.setStep(IRepairHandleService.FEEDBACK); + iRepairHandleService.updateById(loadRepairHandle); + } else { + //否则生成新的记录 + loadRepairHandle.setStep(IRepairHandleService.FEEDBACK); + repairHandle = iRepairHandleService.updateByRepairIdHandleTodo(loadRepairHandle); + } + + //更改待办记录 + repairTodo.setHandleTime(loadRepairHandle.getHappenTime()); + repairTodo.setFeedbackTime(loadRepairHandle.getHappenTime()); + repairTodo.setStep(loadRepairHandle.getStep()); + updateById(repairTodo); + + //关联附件 + iRepairFileService.updateHandleIdByTempHandleId(tempHandleId, repairHandle.getHandleId()); + + //更新详情表-实际完成时间 + Repair repair = new Repair(); + repair.setRepairId(repairTodo.getRepairId()); + repair.setRealityTime(loadRepairHandle.getHappenTime()); + //更新标签 + //标签字符全量插入 + if (labels != null) { + repair.setLabel(String.join(",", labels)); + } + //删除旧的标签 + LambdaQueryWrapper qw = new LambdaQueryWrapper<>(); + qw.eq(RepairLabel::getRepairId, repair.getRepairId()); + iRepairLabelService.remove(qw); + //全量标签全量插入 + if (labels != null) { + for (String s : labels) { + RepairLabel label = new RepairLabel(); + label.setName(s); + label.setRepairId(repair.getRepairId()); + iRepairLabelService.save(label); + } + } + + iRepairService.updateById(repair); + + //则推送消息 + try { + Map map = new LinkedHashMap<>(); + map.put("repairId", repairTodo.getRepairId()); + map.put("title", repairTodo.getTitle()); + BusinessSysServer.sendToUser(repairTodo.getUserId(), JSONObject.toJSONString(map)); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + return RestResult.ok(repairHandle.getHandleId()); + } + + @Override + public Map excelDevFields() { + Map map = new LinkedHashMap<>(); + map.put("getRepairId", "运维单号"); + map.put("getTitle", "标题"); + map.put("getFaultDescription", "故障内容"); + map.put("getBusAcceptNo", "业务受理号"); + map.put("getUsername", "申报用户账号"); + map.put("getNickname", "申报用户昵称"); + map.put("getQuestionType", "问题分类"); + map.put("getLabel", "标签"); + map.put("getBusiness", "业务模块"); + map.put("getLaunchTime", "报送时间"); + map.put("getSolveLimitTime", "解决期限时间"); + map.put("getPlannedTime", "计划完成时间"); + map.put("getFeedbackTime", "反馈时间"); + map.put("getEngineer", "运维工程师"); + map.put("getLeaderNickname", "负责人"); + map.put("getOrg", "所属机构"); + map.put("getDept", "所属单位"); + map.put("getPriority", "紧急程度"); + map.put("getUrgency", "优先级"); + map.put("getReminder", "是否催单"); + map.put("getFeedbackTimeSize", "处理时长"); + map.put("getSolveTime", "归档时长"); + map.put("getStep", "处理环节"); + + return map; + } + + @Override + public Map excelBusinessFields() { + Map map = new LinkedHashMap<>(); + map.put("getRepairId", "运维单号"); + map.put("getTitle", "标题"); + map.put("getFaultDescription", "故障内容"); + map.put("getBusAcceptNo", "业务受理号"); + map.put("getUsername", "申报用户账号"); + map.put("getNickname", "申报用户昵称"); + map.put("getBusiness", "业务模块"); + map.put("getBusClassify", "业务分类"); + map.put("getBusStep", "业务环节"); + map.put("getLaunchTime", "报送时间"); + map.put("getSolveLimitTime", "解决期限时间"); + map.put("getFeedbackTime", "反馈时间"); + map.put("getFeedbackTimeSize", "处理时长"); + map.put("getSolveTime", "归档时长"); + map.put("getEngineer", "运维工程师"); + map.put("getOrg", "所属机构"); + map.put("getDept", "所属单位"); + map.put("getPriority", "紧急程度"); + map.put("getReminder", "是否催单"); + map.put("getStep", "处理环节"); + return map; + } + + @Override + public RestResult reminder(String repairId) { + //查询催单记录 + RepairTodo repairTodo = getByRepairId(repairId); + if (repairTodo == null) { + return RestResult.error(ResultCode.USCID_INVALID); + } + + repairTodo.setReminder(repairTodo.getReminder() == null ? 1 : repairTodo.getReminder() + 1); + updateById(repairTodo); + return RestResult.ok(); + } + + @Override + public IPage synthesizeBusinessList(RepairTodoListQuery query) { + Optional unitId = UserBase.getTokenValueByKey("unitId"); + unitId.ifPresent(o -> query.setDeptId(o.toString())); + query.setUsername(null); + query.setUserId(null); + return findList(query); + } + + @Override + public IPage findTodoByEngineer(RepairTodoListQuery query) { + //获取用户token的用户信息 + String username = UserBase.currentUsername(); + Engineer engineer = iEngineerService.getUserByUsername(username); + String[] roles = engineer.getRoles().split(","); + boolean isAdmin = ArrayUtils.contains(roles, "admin"); + query.setEngineerUsername(username); + //如果tabId不是我的待办和拥有管理员则设空 + if (!"toDoList".equals(query.getTabId()) && isAdmin) { + query.setEngineerUsername(null); + } + IPage list = findList(query); + return list; + } + + @Override + public IPage findTodoByBusiness(RepairTodoListQuery query) { + //获取用户token的用户信息 + String userId = UserBase.currentUserId(); + query.setUserId(userId); + IPage list = findList(query); + return list; + } + + @Override + public IPage listByItemId(RepairTodoListQuery query, String itemId) { + Page page = setPage(query); + + IPage todoIPage = new Page<>(); + //总数 + if ("total".equals(itemId)) { + todoIPage = findList(query); + } else if ("resolved".equals(itemId) || "avgResolvedTime".equals(itemId)) { + query.setStep(new String[]{"resolved"}); + todoIPage = findList(query); + } else if ("untreated".equals(itemId)) { + query.setStep(new String[]{"handle", "declare", "assign", "unresolved"}); + todoIPage = findList(query); + } else if ("confirmed".equals(itemId)) { + query.setStep(new String[]{"feedback"}); + todoIPage = findList(query); + } else if ("oneSuccess".equals(itemId)) { + query.setStep(new String[]{"feedback"}); + todoIPage = repairHandleMapper.listResultSecond(page, query, 1); + } else if ("twoSuccess".equals(itemId)) { + query.setStep(new String[]{"feedback"}); + todoIPage = repairHandleMapper.listResultSecond(page, query, 2); + } else if ("threeSuccess".equals(itemId)) { + query.setStep(new String[]{"feedback"}); + todoIPage = repairHandleMapper.listResultSecond(page, query, 3); + } else if (itemId.startsWith("labelBusClassify")) { + query.setBusClassify(itemId.replace("labelBusClassify", "")); + todoIPage = findList(query); + } else if (itemId.startsWith("labelBusStep")) { + query.setBusStep(itemId.replace("labelBusStep", "")); + todoIPage = findList(query); + } else if ("avgFeedbackTime".equals(itemId)) { + query.setStep(new String[]{"feedback", "resolved"}); + todoIPage = findList(query); + } +// else { +// todoIPage = repairTodoMapper.listByItemId(page, query, itemId); +// } + return todoIPage; + } + + @Override + public void exportListByItemId(HttpServletResponse response, RepairTodoListQuery query, String itemId, String type) throws IOException { + Page page = setPage(query).setCurrent(0).setSize(10000000000000000L); + + IPage todoIPage; + if (query.getTodoIds() != null && query.getTodoIds().length > 0) { + todoIPage = repairTodoMapper.listByTodoId(page, query.getTodoIds()); + } else { + query.setCurrent((int) page.getCurrent()); + query.setSize((int) page.getSize()); + todoIPage = listByItemId(query, itemId); + } + List list = new ArrayList<>(); + List records = todoIPage.getRecords(); + int i = 0; + for (RepairTodo repairTodo : records) { + RepairTodoExcel repairTodoExcel = new RepairTodoExcel(); + BeanUtils.copyProperties(repairTodo, repairTodoExcel); + repairTodoExcel.setNo(++i); + list.add(repairTodoExcel); + } + //找出最大的时间 + LocalDateTime launchTimeMax = records.stream().max((o1, o2) -> { + boolean after = o1.getLaunchTime().isBefore(o2.getLaunchTime()); + return after ? 0 : 1; + }).map(RepairTodo::getLaunchTime).orElse(null); + LocalDateTime launchTimeMin = records.stream().min((o1, o2) -> { + boolean before = o1.getLaunchTime().isAfter(o2.getLaunchTime()); + return before ? 1 : 0; + }).map(RepairTodo::getLaunchTime).orElse(null); + + String date = ""; + if (launchTimeMin != null) { + date = launchTimeMin.toLocalDate().toString(); + } + if (launchTimeMax != null) { + String maxDate = launchTimeMax.toLocalDate().toString(); + if (!date.equals(maxDate)) { + date += " - " + maxDate; + } + } + + String fileName = new String(("运维报障系统" + date + "报障记录.xlsx").getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1); + //response为HttpServletResponse对象 + response.setContentType("application/vnd.ms-excel;charset=utf-8"); + response.setHeader("Content-Disposition", "attachment; filename=" + fileName); + + OutputStream os = response.getOutputStream(); + + //根据字段列表,导出那些表头字段 + String[] fields = query.getFields(); + List exportFields = new ArrayList<>(); + List> titles = new ArrayList<>(); + Map fieldsMap; + if ("dev".equals(type)) { + fieldsMap = excelDevFields(); + } else { + fieldsMap = excelBusinessFields(); + } + List fieldName = new ArrayList<>(); + //大标题 + fieldName.add("运维报障系统 " + date + " 报障记录"); + //序号 + fieldName.add("序号"); + titles.add(fieldName); + //生成表头 + if (fields != null && fields.length > 0) { + for (String fieldId : fieldsMap.keySet()) { + boolean contains = ArrayUtils.contains(fields, fieldId); + if (contains) { + fieldName = new ArrayList<>(); + fieldName.add(fieldsMap.get(fieldId)); + titles.add(fieldName); + exportFields.add(fieldId); + } + } + } else { + //默认导出所有表头 + for (String value : fieldsMap.values()) { + fieldName = new ArrayList<>(); + fieldName.add(value); + titles.add(fieldName); + } + exportFields.addAll(fieldsMap.keySet()); + } + + List> data = new ArrayList<>(); + try { + for (RepairTodoExcel repairTodoExcel : list) { + Class aClass = repairTodoExcel.getClass(); + List item = new ArrayList<>(); + item.add(repairTodoExcel.getNo()); + for (String field : exportFields) { + Method method = aClass.getMethod(field); + Object value = method.invoke(repairTodoExcel); + item.add(value); + } + data.add(item); + } + } catch (Exception e) { + log.error(e.getMessage(), e); + } + EasyExcel.write(os).head(titles).useDefaultStyle(false).automaticMergeHead(false) + .registerWriteHandler(new CustomRowCellWriteHandler()) + .registerConverter(new LocalDateTimeConverter()) + .sheet(date + "报障清单").doWrite(data); + + os.close(); + } + + @Override + public IPage synthesizeEngineerList(RepairTodoListQuery query) { + Optional source = UserBase.getTokenValueByKey("source"); + source.ifPresent(o -> { + query.setSource(Arrays.asList(source.get().toString().split(","))); + }); + return findList(query); + } + + @Override + public IPage leaderTodo(RepairTodoListQuery query) { + String username = UserBase.currentUsername(); + query.setLeaderUsername(username); + return findList(query); + } + + @Override + public RestResult batchAssign(List repairHandleList) { + AtomicInteger atomicInteger = new AtomicInteger(); + for (RepairHandle repairHandle : repairHandleList) { + new Thread(() -> { + assign(repairHandle); + int finishedNum = atomicInteger.incrementAndGet(); + + synchronized (atomicInteger) { + if (finishedNum == repairHandleList.size()) { + atomicInteger.notify(); + } + } + }).start(); + } + synchronized (atomicInteger) { + try { + atomicInteger.wait(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + return RestResult.ok(); + } +} + diff --git a/src/main/java/com/chinaweal/youfool/devops/repair/service/impl/StatisticServiceImpl.java b/src/main/java/com/chinaweal/youfool/devops/repair/service/impl/StatisticServiceImpl.java new file mode 100644 index 0000000..1279c5f --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/repair/service/impl/StatisticServiceImpl.java @@ -0,0 +1,286 @@ +package com.chinaweal.youfool.devops.repair.service.impl; + +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.enums.WriteDirectionEnum; +import com.alibaba.excel.write.metadata.WriteSheet; +import com.alibaba.excel.write.metadata.fill.FillConfig; +import com.chinaweal.youfool.devops.repair.controller.query.RepairTodoListQuery; +import com.chinaweal.youfool.devops.repair.mapper.RepairHandleMapper; +import com.chinaweal.youfool.devops.repair.mapper.RepairMapper; +import com.chinaweal.youfool.devops.repair.mapper.RepairSummaryMapper; +import com.chinaweal.youfool.devops.repair.mapper.RepairTodoMapper; +import com.chinaweal.youfool.devops.repair.service.IRepairSummaryService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.OutputStream; +import java.math.BigDecimal; +import java.nio.charset.StandardCharsets; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; + +import static com.chinaweal.youfool.devops.repair.service.IRepairHandleService.FEEDBACK; + + +/** + * 统计 + */ +@Service +@Slf4j +public class StatisticServiceImpl { + @Resource + private RepairTodoMapper repairTodoMapper; + @Resource + private RepairMapper repairMapper; + @Resource + private RepairHandleMapper repairHandleMapper; + @Resource + private RepairSummaryMapper repairSummaryMapper; + + public List> groupOrgCount(RepairTodoListQuery query) { + List> list = new ArrayList<>(); + List orgs = IRepairSummaryService.getOrgNameList(); + for (int i = 0; i < orgs.size(); i++) { + String org = orgs.get(i); + Map map = new LinkedHashMap<>(); + query.setOrg(org); + Map data = repairTodoMapper.getWhole(query); + BigDecimal total = (BigDecimal) data.get("total"); + BigDecimal resolved = (BigDecimal) data.get("resolved"); + BigDecimal feedback = (BigDecimal) data.get("feedback"); + BigDecimal unresolved = (BigDecimal) data.get("unresolved"); + BigDecimal handleAndDeclare = (BigDecimal) data.get("handleAndDeclare"); + map.put("no", i + 1); + map.put("name", org); + map.put("total", total); + map.put("resolved", resolved); + map.put("resolvedRate", total.compareTo(BigDecimal.valueOf(0)) > 0 ? (resolved.multiply(BigDecimal.valueOf(100)) + .divide(total, 1, BigDecimal.ROUND_HALF_UP) + "%") : 0); + map.put("feedback", feedback); + map.put("feedbackRate", total.compareTo(BigDecimal.valueOf(0)) > 0 ? (feedback.multiply(BigDecimal.valueOf(100)) + .divide(total, 1, BigDecimal.ROUND_HALF_UP) + "%") : 0); + map.put("unresolved", unresolved); + map.put("unresolvedRate", total.compareTo(BigDecimal.valueOf(0)) > 0 ? (unresolved.multiply(BigDecimal.valueOf(100)) + .divide(total, 1, BigDecimal.ROUND_HALF_UP) + "%") : 0); + map.put("handleAndDeclare", handleAndDeclare); + map.put("handleAndDeclareRate", total.compareTo(BigDecimal.valueOf(0)) > 0 ? (handleAndDeclare.multiply(BigDecimal.valueOf(100)) + .divide(total, 1, BigDecimal.ROUND_HALF_UP) + "%") : 0); + list.add(map); + } + return list; + } + + public void exportGroupOrg(RepairTodoListQuery query, HttpServletResponse response) throws IOException { + String fileName = new String(("各单位报障统计.xlsx").getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1); + //response为HttpServletResponse对象 + response.setContentType("application/vnd.ms-excel;charset=utf-8"); + response.setHeader("Content-Disposition", "attachment; filename=" + fileName); + OutputStream os = response.getOutputStream(); + + String templateFileName = this.getClass().getResource("/excel/shijuyugequbaozhantongji.xlsx").getPath(); + ExcelWriter excelWriter = EasyExcel.write(os).withTemplate(templateFileName).build(); + WriteSheet writeSheet = EasyExcel.writerSheet().build(); + FillConfig fillConfig = FillConfig.builder().direction(WriteDirectionEnum.VERTICAL).forceNewRow(Boolean.TRUE).build(); + List> list = groupOrgCount(query); + excelWriter.fill(list, fillConfig, writeSheet); + + Map map = new HashMap<>(); + //处理时间 + if (query.getLaunchTimeStart() != null) { + String start = query.getLaunchTimeStart().format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")); + String end = query.getLaunchTimeEnd().format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")); + map.put("date", start + " 至 " + end); + } else { + map.put("date", "全部"); + } + + //合计 + BigDecimal total = list.stream().map(x -> (BigDecimal) x.get("total")).reduce(BigDecimal.ZERO, BigDecimal::add); + BigDecimal resolved = list.stream().map(x -> (BigDecimal) x.get("resolved")).reduce(BigDecimal.ZERO, BigDecimal::add); + BigDecimal feedback = list.stream().map(x -> (BigDecimal) x.get("feedback")).reduce(BigDecimal.ZERO, BigDecimal::add); + BigDecimal unresolved = list.stream().map(x -> (BigDecimal) x.get("unresolved")).reduce(BigDecimal.ZERO, BigDecimal::add); + BigDecimal handleAndDeclare = list.stream().map(x -> ((BigDecimal) x.get("handleAndDeclare"))).reduce(BigDecimal.ZERO, BigDecimal::add); + map.put("total", total); + map.put("resolved", resolved); + map.put("resolvedRate", total.compareTo(BigDecimal.valueOf(0)) > 0 ? (resolved.multiply(BigDecimal.valueOf(100)) + .divide(total, 1, BigDecimal.ROUND_HALF_UP) + "%") : 0); + map.put("feedback", feedback); + map.put("feedbackRate", total.compareTo(BigDecimal.valueOf(0)) > 0 ? (feedback.multiply(BigDecimal.valueOf(100)) + .divide(total, 1, BigDecimal.ROUND_HALF_UP) + "%") : 0); + map.put("unresolved", unresolved); + map.put("unresolvedRate", total.compareTo(BigDecimal.valueOf(0)) > 0 ? (unresolved.multiply(BigDecimal.valueOf(100)) + .divide(total, 1, BigDecimal.ROUND_HALF_UP) + "%") : 0); + map.put("handleAndDeclare", handleAndDeclare); + map.put("handleAndDeclareRate", total.compareTo(BigDecimal.valueOf(0)) > 0 ? (handleAndDeclare.multiply(BigDecimal.valueOf(100)) + .divide(total, 1, BigDecimal.ROUND_HALF_UP) + "%") : 0); + + excelWriter.fill(map, writeSheet); + excelWriter.finish(); + } + + public Map sumTotalType(RepairTodoListQuery query) { + BigDecimal total = repairHandleMapper.countStep(query, "total"); + BigDecimal resolved = repairHandleMapper.countStep(query, "resolved"); + BigDecimal untreated = repairHandleMapper.countStep(query, "untreated"); + BigDecimal confirmed = repairHandleMapper.countStep(query, "confirmed"); + + Map data = new LinkedHashMap<>(); + //报障总数量 + data.put("total", total); + data.put("resolved", resolved); + data.put("untreated", untreated); + data.put("confirmed", confirmed); + + return data; + } + + public List> sumQuestionType(RepairTodoListQuery query) { + List> bodyList = new ArrayList<>(); + //报障总数量 + List> list = repairMapper.groupByQuestionTypeCount(query); + for (Map dbData : list) { + Map data = new HashMap<>(); + data.put("name", dbData.getOrDefault("questionType", "其他")); + data.put("number", dbData.get("number")); + bodyList.add(data); + } + return bodyList; + } + + public List> sumSuccess(RepairTodoListQuery query) { + List> bodyList = new ArrayList<>(); + BigDecimal oneSuccess = repairHandleMapper.countResultSecond(query, 1); + BigDecimal twoSuccess = repairHandleMapper.countResultSecond(query, 2); + BigDecimal threeSuccess = repairHandleMapper.countResultSecond(query, 3); + Map one = new LinkedHashMap<>(); + one.put("name", "处理1次"); + one.put("number", oneSuccess); + + Map two = new LinkedHashMap<>(); + two.put("name", "处理2次"); + two.put("number", twoSuccess); + + + Map three = new LinkedHashMap<>(); + three.put("name", "处理3次及以上"); + three.put("number", threeSuccess); + + bodyList.add(one); + bodyList.add(two); + bodyList.add(three); + + return bodyList; + } + + public Map sumEfficiency(RepairTodoListQuery query) { + + List> list = repairSummaryMapper.sumTotalByOrgAndDay(query.getLaunchTimeStart(), query.getLaunchTimeEnd(), query.getOrgListLike()); + + Map bodyMap = new HashMap<>(); + Map item; + List> totalList = new ArrayList<>(); + for (Map dbData : list) { + BigDecimal handleTotal = (BigDecimal) dbData.get("handleTotal"); + item = new LinkedHashMap<>(); + item.put("date", dbData.get("dateStr")); + item.put("reportTotal", dbData.get("reportTotal")); + item.put("handleTotal", handleTotal); + item.put("busTotal", dbData.get("busTotal")); + item.put("faultRate", 0);//todo + item.put("resSpeed", handleTotal.divide(BigDecimal.valueOf(8), 0, BigDecimal.ROUND_HALF_UP)); + totalList.add(item); + } + //判断结束时间是否包含当天,如是则需要实时查询当天数据(因为汇总表只有昨天的数据) + LocalDate toDay = LocalDate.now(); + if (query.getLaunchTimeEnd() == null || query.getLaunchTimeEnd().toLocalDate().isAfter(toDay) + || query.getLaunchTimeEnd().toLocalDate().isEqual(toDay)) { + LocalDateTime startTime = toDay.atStartOfDay(); + LocalDateTime endTime = startTime.plusDays(1).minusSeconds(1); + + Long reportTotal = repairTodoMapper.countByLaunchTimeAndLikeOrg(startTime, endTime, query.getOrgListLike()); + Long handleTotal = repairHandleMapper.countDistinctByTimeAndOrgAndStep(startTime, endTime, query.getOrgListLike(), FEEDBACK); + + item = new LinkedHashMap<>(); + item.put("date", toDay.toString()); + item.put("reportTotal", reportTotal); + item.put("handleTotal", handleTotal); + item.put("busTotal", 0);//todo + item.put("faultRate", 0);//todo + item.put("resSpeed", BigDecimal.valueOf(handleTotal).divide(BigDecimal.valueOf(8), 0, BigDecimal.ROUND_HALF_UP)); + totalList.add(item); + } + + bodyMap.put("totalList", totalList); + //日期范围数组 + List dateRange = new ArrayList<>(); + //取出最后一组数据,遍历出日期 + for (Map map : totalList) { + dateRange.add(map.get("date")); + } + bodyMap.put("dateRange", dateRange); + + return bodyMap; + } + + public Map sumQuestionTopDay(RepairTodoListQuery query) { + Map bodyMap = new HashMap<>(); + Map topMap = new LinkedHashMap<>(); + + //判断结束时间是否包含当天,如是则需要实时查询当天数据(因为汇总表只有昨天的数据) + LocalDate toDay = LocalDate.now(); + RepairTodoListQuery toDayQuery = null; + if (query.getLaunchTimeEnd() == null || query.getLaunchTimeEnd().toLocalDate().isAfter(toDay) + || query.getLaunchTimeEnd().toLocalDate().isEqual(toDay)) { + toDayQuery = new RepairTodoListQuery(); + toDayQuery.setLaunchTimeStart(toDay.atStartOfDay()); + toDayQuery.setLaunchTimeEnd(toDay.plusDays(1).atStartOfDay().minusSeconds(1)); + } + + //查询前五的问题分类总数 + List> top5 = repairSummaryMapper.getGroupQuestionTop(query.getLaunchTimeStart(), query.getLaunchTimeEnd(), query.getOrgListLike()); + List> list = new ArrayList<>(); + for (Map map : top5) { + list = new ArrayList<>(); + String name = String.valueOf(map.get("name")); + //根据问题分类名称查询每天最新的列表 + List> dbList = repairSummaryMapper.sumTotalByOrgAndQuestionDay(query.getLaunchTimeStart(), + query.getLaunchTimeEnd(), name, query.getOrgListLike()); + + for (Map dbData : dbList) { + map = new LinkedHashMap<>(); + map.put("date", dbData.get("dateStr")); + map.put("reportTotal", dbData.get("reportTotal")); + list.add(map); + } + //是否需要补上今天实时的数据 + if (toDayQuery != null) { + toDayQuery.setQuestionType(name); + BigDecimal number = repairMapper.countByQuestionType(toDayQuery); + map = new LinkedHashMap<>(); + map.put("date", toDay.toString()); + map.put("reportTotal", number); + list.add(map); + } + + topMap.put(name, list); + } + bodyMap.put("top", topMap); + //日期范围数组 + List dateRange = new ArrayList<>(); + //取出最后一组数据,遍历出日期 + for (Map map : list) { + dateRange.add(map.get("date")); + } + bodyMap.put("dateRange", dateRange); + + return bodyMap; + } + + +} diff --git a/src/main/java/com/chinaweal/youfool/devops/util/VerifyCode.java b/src/main/java/com/chinaweal/youfool/devops/util/VerifyCode.java new file mode 100644 index 0000000..ce3f7d1 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/util/VerifyCode.java @@ -0,0 +1,76 @@ +package com.chinaweal.youfool.devops.util; + +/*对图片进行处理的类和方法*/ + +import javax.imageio.ImageIO; +import javax.servlet.http.HttpServletRequest; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Random; + +public class VerifyCode { + + public static String drawRandomText(int width, int height, OutputStream output, HttpServletRequest request) { + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + Graphics2D graphics = (Graphics2D) image.getGraphics(); + graphics.setColor(Color.WHITE);//设置画笔颜色-验证码背景色 + graphics.fillRect(0, 0, width, height);//填充背景 + graphics.setFont(new Font("微软雅黑", Font.BOLD, 40)); + //数字和字母的组合 + String baseNumLetter = "123456789abcdefghijklmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"; + + StringBuffer sBuffer = new StringBuffer(); + int x = 10; //旋转原点的 x 坐标 + String ch = ""; + Random random = new Random(); + for (int i = 0; i < 4; i++) { + graphics.setColor(getRandomColor()); + //设置字体旋转角度 + int degree = random.nextInt() % 30; //角度小于30度 + int dot = random.nextInt(baseNumLetter.length()); + ch = baseNumLetter.charAt(dot) + ""; + sBuffer.append(ch); + //正向旋转 + graphics.rotate(degree * Math.PI / 180, x, 45); + graphics.drawString(ch, x, 45); + //反向旋转 + graphics.rotate(-degree * Math.PI / 180, x, 45); + x += 35; + } + //画干扰线 + for (int i = 0; i < 6; i++) { + // 设置随机颜色 + graphics.setColor(getRandomColor()); + // 随机画线 + graphics.drawLine(random.nextInt(width), random.nextInt(height), + random.nextInt(width), random.nextInt(height)); + } + //添加噪点 + for (int i = 0; i < 30; i++) { + int x1 = random.nextInt(width); + int y1 = random.nextInt(height); + graphics.setColor(getRandomColor()); + graphics.fillRect(x1, y1, 2, 2); + } + //记录session + request.getSession().setAttribute("vcode", sBuffer.toString()); + try { + ImageIO.write(image, "png", output); + } catch (IOException e) { + e.printStackTrace(); + } + return sBuffer.toString(); + } + + /** + * 随机取色 + */ + private static Color getRandomColor() { + Random ran = new Random(); + Color color = new Color(ran.nextInt(256), + ran.nextInt(256), ran.nextInt(256)); + return color; + } +} diff --git a/src/main/java/com/chinaweal/youfool/devops/websocket/controller/TestWebSocketController.java b/src/main/java/com/chinaweal/youfool/devops/websocket/controller/TestWebSocketController.java new file mode 100644 index 0000000..84632a1 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/websocket/controller/TestWebSocketController.java @@ -0,0 +1,24 @@ +package com.chinaweal.youfool.devops.websocket.controller; + +import com.chinaweal.youfool.devops.websocket.server.BusinessSysServer; +import com.chinaweal.youfool.framework.springboot.rest.RestResult; +import com.github.xiaoymin.knife4j.annotations.ApiSort; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Api(tags = "1.WebSocket测试") +@ApiSort(1) +@RestController +@RequestMapping("/websocket") +public class TestWebSocketController { + + @ApiOperation(value = "1.测试业务系统发送", position = 1) + @GetMapping("/countRepairStepByUsername") + public RestResult countRepairStepByUsername(String username, String message) { + BusinessSysServer.sendToUser(username, message); + return RestResult.ok(); + } +} diff --git a/src/main/java/com/chinaweal/youfool/devops/websocket/server/BusinessSysServer.java b/src/main/java/com/chinaweal/youfool/devops/websocket/server/BusinessSysServer.java new file mode 100644 index 0000000..60f12b8 --- /dev/null +++ b/src/main/java/com/chinaweal/youfool/devops/websocket/server/BusinessSysServer.java @@ -0,0 +1,122 @@ +package com.chinaweal.youfool.devops.websocket.server; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.websocket.*; +import javax.websocket.server.PathParam; +import javax.websocket.server.ServerEndpoint; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 与业务系统的通信 websocket + * + * @author + */ +@ServerEndpoint("/websocket/businessSys/{userId}") +@Component +@Slf4j +public class BusinessSysServer { + + /** + * 存储起来,一个用户账号可能多页面打开,存储列表 + */ + private static final ConcurrentHashMap> WEB_SOCKET_SET = new ConcurrentHashMap<>(); + private Session session; + private String userId; + + /** + * 连接建立成功调用的方法 + * + * @param userId 用户唯一标示 + * @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据 + */ + @OnOpen + public void onOpen(@PathParam(value = "userId") String userId, Session session) { + pushSessionByUserId(userId, session); + log.debug("用户名:{},sessionId:{},以系统连接建立成功", userId, session.getId()); + } + + private void pushSessionByUserId(String userId, Session session) { + this.session = session; + this.userId = userId; + List list = WEB_SOCKET_SET.getOrDefault(userId, new ArrayList<>()); + list.add(session); + WEB_SOCKET_SET.put(userId, list); + } + + private void removeSessionByUserIdOrSessionId() { + List sessions = WEB_SOCKET_SET.get(userId); + if (sessions == null || sessions.isEmpty()) { + return; + } + sessions.removeIf(next -> next == null || next.getId().equals(session.getId())); + if (sessions.isEmpty()) { + WEB_SOCKET_SET.remove(userId); + } + } + + + /** + * 连接关闭调用的方法 + */ + @OnClose + public void onClose() { + removeSessionByUserIdOrSessionId(); + log.debug("用户名退出:{},当前sessionId:{}", userId, session.getId()); + } + + /** + * 收到客户端消息后调用的方法 + * + * @param message 客户端发送过来的消息 + * @param session 可选的参数 + */ + @OnMessage + public void onMessage(String message, Session session) { + log.debug("来自客户端的消息:" + message); + } + + /** + * 给指定的人发送消息 + * + * @param message + */ + public static void sendToUser(String sendUserId, String message) { + List sessions = WEB_SOCKET_SET.get(sendUserId); + if (sessions != null) { + for (Session item : sessions) { + if (item != null && item.isOpen()) { + item.getAsyncRemote().sendText(message); + } + } + } + } + + /** + * 发生错误时调用 + * + * @param session + * @param error + */ + @OnError + public void onError(Session session, Throwable error) { +// log.error(error.getMessage(), error); + } + + /** + * 发送消息 + * + * @param message + * @throws IOException + */ + public void sendMessage(String message) throws IOException { + //同步发送 + this.session.getBasicRemote().sendText(message); + //异步发送 + //this.session.getAsyncRemote().sendText(message); + } +} diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml new file mode 100644 index 0000000..42012ac --- /dev/null +++ b/src/main/resources/application-dev.yml @@ -0,0 +1,34 @@ +logging: + level: + dao: debug + youfool.dao: info + com.chinaweal.youfool.framework.springboot.log: debug + com.chinaweal.youfool.devops: debug +spring: + datasource: + youfool: + url: jdbc:oracle:thin:@172.22.80.186:1521:chinaweal + username: devops + password: 123456 + devops: + url: jdbc:oracle:thin:@172.22.80.186:1521:chinaweal + username: devops + password: 123456 +file: + devopsDir: D:\chinaweal\gitea-code\youfool-project\youfool-devops\upload + +business: + fsLoginUrl: http://121.8.152.130:9888/tzrysb/user/loginDevops + sdLoginUrl: http://121.8.152.130:9888/tzrysb/user/loginDevops + fsUserInfoUrl: http://121.8.152.130:9888/tzrysb/user/searchUserDevops + sdUserInfoUrl: http://121.8.152.130:9888/tzrysb/user/searchUserDevops + +#运维通报机器人 +noticeWebhookKeys: 48de65c6-b068-4926-be25-e5935f4d1702,48de65c6-b068-4926-be25-e5935f4d1702#运维通报机器人 +#数据账号密码过期机器人 +dbWebhookKeys: 48de65c6-b068-4926-be25-e5935f4d1702 + +applicationName: devOps + +swagger: + enable: true diff --git a/src/main/resources/application-fs146prod.yml b/src/main/resources/application-fs146prod.yml new file mode 100644 index 0000000..315eba9 --- /dev/null +++ b/src/main/resources/application-fs146prod.yml @@ -0,0 +1,34 @@ +logging: + level: + dao: info + youfool.dao: info + com.chinaweal.youfool.framework.springboot.log: debug + com.chinaweal.youfool.devops: info + filePath: D:\apache-tomcat-8.5.53_9088-devops\logs +spring: + datasource: + youfool: + url: jdbc:oracle:thin:@19.130.241.145:1521:FSAMRDATA + username: devops + password: Supper#2020 + devops: + url: jdbc:oracle:thin:@19.130.241.145:1521:FSAMRDATA + username: devops + password: Supper#2020 + +file: + devopsDir: D:\apache-tomcat-8.5.53_9088-devops\webapps\upload + +business: + fsLoginUrl: http://19.130.241.146:9888/tzrysb/user/loginDevops + sdLoginUrl: http://19.202.179.137:9888/tzrysb/user/loginDevops + fsUserInfoUrl: http://19.130.241.146:9888/tzrysb/user/searchUserDevops + sdUserInfoUrl: http://19.202.179.137:9888/tzrysb/user/searchUserDevops + +#运维通报机器人 +noticeWebhookKeys: 2eacc126-74d2-4360-a88e-369c83aed8cf,94106362-31b8-4dc1-b1ea-239196095aa5,bad2a6aa-9cc8-4f82-9e46-aff9f13a2efb +#数据账号密码过期机器人 +dbWebhookKeys: 45d1bda2-c0b9-45c3-b640-be77f7a0726d,2eacc126-74d2-4360-a88e-369c83aed8cf,3dcb2f2c-cdf1-43a0-b765-882676aa7f41,7fa4ae32-9721-4175-a812-962ad38c6e3b + +swagger: + enable: false diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..96875ad --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,82 @@ +logging: + level: + root: info +spring: + profiles: + active: fs146prod + application: + name: youfoo-devops + datasource: + #https://gitee.com/wenshao/druid/tree/master/druid-spring-boot-starter + #https://github.com/alibaba/druid/wiki/DruidDataSource%E9%85%8D%E7%BD%AE + youfool: + filters: stat + initial-size: 2 + min-idle: 1 + max-active: 20 + max-wait: 30000 + time-between-eviction-runs-millis: 60000 + min-evictable-idle-time-millis: 300000 + validation-query: select 1 from dual + devops: + filters: stat + initial-size: 2 + min-idle: 1 + max-active: 20 + max-wait: 30000 + time-between-eviction-runs-millis: 60000 + min-evictable-idle-time-millis: 300000 + validation-query: select 1 from dual + druid: + web-stat-filter: + enabled: true + stat-view-servlet: + enabled: true + url-pattern: /druid/* + login-username: admin + login-password: 123456 + servlet: + multipart: + max-file-size: 100MB + max-request-size: 100MB + +restLog: + ignoreServletPath: /druid,/swagger-resources,/v2/api-docs,/webjars,/websocket + isSaveDb: false +# ignoreSuffix: .css,.jpg,.png,.icon,.html,.js + +jwt: + id: devops + secret: 64faa93ed3454feeab946cc3a526eea0 + ttlMillis: 36000000 #后台10小时前端cookie只记录120分钟 + +#用户的密码sm3秘钥 +sm3: + secret: 82b0832fdaac473b83225ab92e7e3c3d + +rsa: + publicKey: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDfZm8rbPK8bF1Qv0yw3heNzzQOwDlEU75Yl8gF6VfMN9R4hBjJ73x+DbxYXo7//WPIiY8iZuLsXnI7SUUi7Zy3jwC+4ylmVkXou4Wz/rXeLLw+4RgOUC3KCvWRr2xgT1jzaQuU/dEhZefGk/IU1GFd5Vqbkikmr6s88Uqbk4kKWwIDAQAB + privateKey: MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAN9mbyts8rxsXVC/TLDeF43PNA7AOURTvliXyAXpV8w31HiEGMnvfH4NvFhejv/9Y8iJjyJm4uxecjtJRSLtnLePAL7jKWZWRei7hbP+td4svD7hGA5QLcoK9ZGvbGBPWPNpC5T90SFl58aT8hTUYV3lWpuSKSavqzzxSpuTiQpbAgMBAAECgYEAiIY+PCipszL6WCWAhbpEZLqTEsywcqxG8DdZ2xr+N+SKqVf5GjeMOjDEwLCQ7ap594zxd1GvLkqNvuOJJ85UbcjeVWSjHoer/TXlJg4xT/7kWrmSxWjldOiayfRfIfzu64WQsWNhH2BLc+iTilTE2cO3gBjAJyO5yGiBt5ZJKlECQQDwnllq9kjkdyqXDoxFukyqXj5vH2+kEj9lJ2MYgD8dZvp15BunC/Y2IlEjouID8w3I21jDD7PoIZImcjB6LOv5AkEA7a5Pig4jGKaXAyR20CuDMLCcylKSiu2n3u5pmr6AmXSWRpXs6nnn/iir96doGDxdFUkQz3Fmor2JQkUZL/618wJAE4hHKe+kKyehRXHg4SgmYQ4Vc1/R6Dey/bscyDhg5zocysUhmYXXDr3qaEIoprlsPQnRQsRbjlRrUMOkO8a5wQJBAMvVTYlMDnU5iRC82Ng2ONAs5onsvpg+sFTTieWXspnoDmiCcyezXG3vW2uMOg1u1zVF8BC3ZBn1Ch23PJ6YhlkCQGscxzS2fQfjkXXu2n+E4UXC4wp4cnFK0UyKRfUOL60X1f3hCR+6bIbGqiJTGdYn7oC6Sub0z555QGT9vkRlgG4= + +#knife4j: +# production: false +# basic: +# enable: true +# username: admin +# password: 123456 + +forest: + backend: okhttp3 # 后端HTTP框架(默认为 okhttp3) + max-connections: 1000 # 连接池最大连接数(默认为 500) + max-route-connections: 500 # 每个路由的最大连接数(默认为 500) + timeout: 30000 # 请求超时时间,单位为毫秒(默认为 3000) + connect-timeout: 30000 # 连接超时时间,单位为毫秒(默认为 timeout) + read-timeout: 30000 # 数据读取超时时间,单位为毫秒(默认为 timeout) + max-retry-count: 0 # 请求失败后重试次数(默认为 0 次不重试) + logEnabled: true # 打开或关闭日志(默认为 true) + log-request: true # 打开/关闭Forest请求日志(默认为 true) + log-response-status: true # 打开/关闭Forest响应状态日志(默认为 true) + log-response-content: true # 打开/关闭Forest响应内容日志(默认为 false) + +#数据库密码监控账号列表 +dbUsernames: AICSCR,AICORG,SPEEQU,ZKRUSER,GOLDENGATE,DEVOPS,SYSTEM,SPEE_OS,DWDDATA,DIMDATA,AICBLACK,CRUSER,ZSJUSER,FJYUSER,CXAICSCR,XIAOBAO,FSREPORT \ No newline at end of file diff --git a/src/main/resources/excel/shijuyugequbaozhantongji.xlsx b/src/main/resources/excel/shijuyugequbaozhantongji.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..6a438a599b0d6c96c73265ac9ae50f92eb5507f5 GIT binary patch literal 13340 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 ?ITIzKgiA<=8H!){1sTXl06tgb`2({0; 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/excel/报障运维单模板.xlsx b/src/main/resources/excel/报障运维单模板.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..ed4e8bba2499e78d53c652dd21dfc4edadc23674 GIT binary patch literal 13564 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..e862ae2 --- /dev/null +++ b/src/main/resources/logback-spring.xml @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + ${consolePattern} + + + + + + + ${filePattern} + + ${logFilePath}/${logFileName}.log + + ${logFilePath}/${logFileName}.%d{yyyy-MM-dd}.%i.log + ${LOG_FILE_MAX_SIZE:-5MB} + ${LOG_FILE_MAX_HISTORY:-0} + + + + + + ${filePattern} + + ${logFilePath}/${logFileName}-debug.log + + ${logFilePath}/${logFileName}-debug.%d{yyyy-MM-dd}.%i.log + ${LOG_FILE_MAX_SIZE:-5MB} + ${LOG_FILE_MAX_HISTORY:-0} + + + DEBUG + ACCEPT + DENY + + + + + + ${filePattern} + + ${logFilePath}/${logFileName}-info.log + + ${logFilePath}/${logFileName}-info.%d{yyyy-MM-dd}.%i.log + ${LOG_FILE_MAX_SIZE:-5MB} + ${LOG_FILE_MAX_HISTORY:-0} + + + INFO + ACCEPT + DENY + + + + + + ${filePattern} + + ${logFilePath}/${logFileName}-warn.log + + ${logFilePath}/${logFileName}-warn.%d{yyyy-MM-dd}.%i.log + ${LOG_FILE_MAX_SIZE:-5MB} + ${LOG_FILE_MAX_HISTORY:-0} + + + WARN + ACCEPT + DENY + + + + + + ${filePattern} + + ${logFilePath}/${logFileName}-error.log + + ${logFilePath}/${logFileName}-error.%d{yyyy-MM-dd}.%i.log + ${LOG_FILE_MAX_SIZE:-5MB} + ${LOG_FILE_MAX_HISTORY:-0} + + + ERROR + ACCEPT + DENY + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/mybatis/mapper/base/DictMapper.xml b/src/main/resources/mybatis/mapper/base/DictMapper.xml new file mode 100644 index 0000000..5da7aea --- /dev/null +++ b/src/main/resources/mybatis/mapper/base/DictMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/src/main/resources/mybatis/mapper/base/TaskFileMapper.xml b/src/main/resources/mybatis/mapper/base/TaskFileMapper.xml new file mode 100644 index 0000000..a6fcce3 --- /dev/null +++ b/src/main/resources/mybatis/mapper/base/TaskFileMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/src/main/resources/mybatis/mapper/base/TaskHandleMapper.xml b/src/main/resources/mybatis/mapper/base/TaskHandleMapper.xml new file mode 100644 index 0000000..e451eae --- /dev/null +++ b/src/main/resources/mybatis/mapper/base/TaskHandleMapper.xml @@ -0,0 +1,10 @@ + + + + + + diff --git a/src/main/resources/mybatis/mapper/base/TaskListMapper.xml b/src/main/resources/mybatis/mapper/base/TaskListMapper.xml new file mode 100644 index 0000000..a0fc7e3 --- /dev/null +++ b/src/main/resources/mybatis/mapper/base/TaskListMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/src/main/resources/mybatis/mapper/leaderassign/AssignMapper.xml b/src/main/resources/mybatis/mapper/leaderassign/AssignMapper.xml new file mode 100644 index 0000000..bb24431 --- /dev/null +++ b/src/main/resources/mybatis/mapper/leaderassign/AssignMapper.xml @@ -0,0 +1,93 @@ + + + + + + diff --git a/src/main/resources/mybatis/mapper/org/EngineerMapper.xml b/src/main/resources/mybatis/mapper/org/EngineerMapper.xml new file mode 100644 index 0000000..93a7683 --- /dev/null +++ b/src/main/resources/mybatis/mapper/org/EngineerMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/src/main/resources/mybatis/mapper/repair/NotificationMapper.xml b/src/main/resources/mybatis/mapper/repair/NotificationMapper.xml new file mode 100644 index 0000000..065c181 --- /dev/null +++ b/src/main/resources/mybatis/mapper/repair/NotificationMapper.xml @@ -0,0 +1,22 @@ + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mybatis/mapper/repair/RepairFileMapper.xml b/src/main/resources/mybatis/mapper/repair/RepairFileMapper.xml new file mode 100644 index 0000000..4626d2e --- /dev/null +++ b/src/main/resources/mybatis/mapper/repair/RepairFileMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/src/main/resources/mybatis/mapper/repair/RepairHandleMapper.xml b/src/main/resources/mybatis/mapper/repair/RepairHandleMapper.xml new file mode 100644 index 0000000..ef486e9 --- /dev/null +++ b/src/main/resources/mybatis/mapper/repair/RepairHandleMapper.xml @@ -0,0 +1,195 @@ + + + + + + + + + + + + + diff --git a/src/main/resources/mybatis/mapper/repair/RepairLabelMapper.xml b/src/main/resources/mybatis/mapper/repair/RepairLabelMapper.xml new file mode 100644 index 0000000..0b534a6 --- /dev/null +++ b/src/main/resources/mybatis/mapper/repair/RepairLabelMapper.xml @@ -0,0 +1,135 @@ + + + + + + + + + + diff --git a/src/main/resources/mybatis/mapper/repair/RepairMapper.xml b/src/main/resources/mybatis/mapper/repair/RepairMapper.xml new file mode 100644 index 0000000..b6a7634 --- /dev/null +++ b/src/main/resources/mybatis/mapper/repair/RepairMapper.xml @@ -0,0 +1,56 @@ + + + + + + + + + + diff --git a/src/main/resources/mybatis/mapper/repair/RepairSummaryMapper.xml b/src/main/resources/mybatis/mapper/repair/RepairSummaryMapper.xml new file mode 100644 index 0000000..fc61552 --- /dev/null +++ b/src/main/resources/mybatis/mapper/repair/RepairSummaryMapper.xml @@ -0,0 +1,69 @@ + + + + + + + + + + diff --git a/src/main/resources/mybatis/mapper/repair/RepairTodoMapper.xml b/src/main/resources/mybatis/mapper/repair/RepairTodoMapper.xml new file mode 100644 index 0000000..2a925b7 --- /dev/null +++ b/src/main/resources/mybatis/mapper/repair/RepairTodoMapper.xml @@ -0,0 +1,290 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/mybatis/mybatis-config.xml b/src/main/resources/mybatis/mybatis-config.xml new file mode 100644 index 0000000..f44707b --- /dev/null +++ b/src/main/resources/mybatis/mybatis-config.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/properties/codeCenerator.properties b/src/main/resources/properties/codeCenerator.properties new file mode 100644 index 0000000..a474dbe --- /dev/null +++ b/src/main/resources/properties/codeCenerator.properties @@ -0,0 +1,22 @@ +#mybatis-plus 代码生成器参数 +#url=jdbc:postgresql://172.22.80.157:5432/pms_dev +#driverName=org.postgresql.Driver +##PostgreSQL schemaName +#schemaName=public +#username=postgres +#password=123456 +#oracle devops +url=jdbc:oracle:thin:@172.22.80.186:1521:chinaweal +driverName=oracle.jdbc.driver.OracleDriver +username=devops +password=123456 +#oracle org +#url=jdbc:oracle:thin:@172.22.80.186:1521:chinaweal +#driverName=oracle.jdbc.driver.OracleDriver +#username=aicorg +#password=123456 +#父包名 +parentPackageName=com.chinaweal.youfool.devops +#mapper文件存放路径 +mapperFilePath=/src/main/resources/mybatis/mapper/ +author=chinaweal \ No newline at end of file diff --git a/src/main/resources/properties/youfool-devops.properties b/src/main/resources/properties/youfool-devops.properties new file mode 100644 index 0000000..606874f --- /dev/null +++ b/src/main/resources/properties/youfool-devops.properties @@ -0,0 +1,7 @@ +applicationName=devOps +#描述 +description=运维管理系统 +#许可 +license=众望通科技 +#版本号 +version=1.0 diff --git a/src/main/resources/spring-timer.xml b/src/main/resources/spring-timer.xml new file mode 100644 index 0000000..25302ff --- /dev/null +++ b/src/main/resources/spring-timer.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/template/daily-report.xlsx b/src/main/resources/template/daily-report.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..c24933435028ed3497bcbfa2f459de593774592c GIT binary patch literal 11780 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 h_g=E`|1174udW~s^C>nX#V*1e*gtt#S#Dj literal 0 HcmV?d00001 diff --git a/src/main/resources/word/yunWeiTongGao.xml b/src/main/resources/word/yunWeiTongGao.xml new file mode 100644 index 0000000..ede0a1b --- /dev/null +++ b/src/main/resources/word/yunWeiTongGao.xml @@ -0,0 +1,3 @@ + + +一二三四五六七八九十一二三四五六七八九十一二三四五六七八chinaweal黄 晓1142020-10-27T07:38:00Z2020-10-27T07:44:00Z2020-10-27T14:11:00Z52641510chaozhou1231771162052-11.8.2.8621佛山市市场监督管理局不公开特 急佛山市市场监督管理局关于佛山市市场监管许可登记一体化系统${year?c}年${month}月运维情况的通报广东众望通科技股份有限公司:为加强对佛山市市场监管许可登记一体化系统(以下简称“系统”)运行情况的管理,市局对系统${year?c}年${month}月的运维情况进行了总结分析,现通报如下:各单位报障情况${month}月,全市各单位报障总数${reportTotal?c}条,日均报障${average}条,环比${reportQoq}。截至${byMonth}月${byDay}日,广东众望通科技股份有限公司)(以下简称“众望通”)已处理${processed?c}条(其中报障人已确认${resolved?c}条,报障人待确认${confirmed?c}条),占比${processedProportion},环比${processedQoq},未处理${untreated?c}条。详情如下:报障单位${month}月报障总数(条)${month}月报障人已确认情况${month}月报障人待确认情况未处理总数(条)历史累计情况总数(条)已确认占比总数(条)待确认占比报障总数(条)待确认总数(条)待确认占比市局${cityData.total}${cityData.resolvedTotal}${cityData.resolvedProportion}${cityData.confirmedTotal}${cityData.confirmedProportion}${cityData.untreated}${cityData.historyTotal?c}${cityData.historyConfirmed}${cityData.historyConfirmedProportion}禅城区局${chanChengData.total}${chanChengData.resolvedTotal}${chanChengData.resolvedProportion}${chanChengData.confirmedTotal}${chanChengData.confirmedProportion}${chanChengData.untreated}${chanChengData.historyTotal?c}${chanChengData.historyConfirmed}${chanChengData.historyConfirmedProportion}南海区局${nanHaiData.total}${nanHaiData.resolvedTotal}${nanHaiData.resolvedProportion}${nanHaiData.confirmedTotal}${nanHaiData.confirmedProportion}${nanHaiData.untreated}${nanHaiData.historyTotal?c}${nanHaiData.historyConfirmed?c}${nanHaiData.historyConfirmedProportion}顺德区局${shunDeData.total}${shunDeData.resolvedTotal}${shunDeData.resolvedProportion}${shunDeData.confirmedTotal}${shunDeData.confirmedProportion}${shunDeData.untreated}${shunDeData.historyTotal?c}${shunDeData.historyConfirmed}${shunDeData.historyConfirmedProportion}高明区局${gaoMingData.total}${gaoMingData.resolvedTotal}${gaoMingData.resolvedProportion}${gaoMingData.confirmedTotal}${gaoMingData.confirmedProportion}${gaoMingData.untreated}${gaoMingData.historyTotal?c}${gaoMingData.historyConfirmed}${gaoMingData.historyConfirmedProportion}三水区局${sanShuiData.total}${sanShuiData.resolvedTotal}${sanShuiData.resolvedProportion}${sanShuiData.confirmedTotal}${sanShuiData.confirmedProportion}${sanShuiData.untreated}${sanShuiData.historyTotal?c}${sanShuiData.historyConfirmed}${sanShuiData.historyConfirmedProportion}合计${allData.total?c}${allData.resolvedTotal?c}${allData.resolvedProportion}${allData.confirmedTotal?c}${allData.confirmedProportion}${allData.untreated?c}${allData.historyTotal?c}${allData.historyConfirmed?c}${allData.historyConfirmedProportion}图1 ${year?c}年${month}月全市各单位报障情况图图2 ${year?c}年${month}运维情况(报障数/处理数)运维趋势图众望通报障解决情况报障未处理情况。${month}月全市报障总数${reportTotal?c}条,未处理${untreated}条,占比${untreatedProportion},环比${untreatedQoq};历史累计全市报障总数${historyTotal?c}条,未处理${historyUntreated?c}条,占比${historyUntreatedProportion},环比${historyUntreatedQoq}。报障解决效率。对本月报障人已确认处理的${allData.resolvedTotal?c}条报障信息做分析,1次处理解决故障数量为${oneHandle.total?c}条,占比${oneHandle.proportion},环比${oneHandle.qoq};2次处理解决故障数量为${twoHandle.total}条,占比${twoHandle.proportion},环比${twoHandle.qoq};3次及以上处理解决故障数量为${threeHandle.total?c}条,占比${threeHandle.proportion},环比${threeHandle.qoq}。每条故障解决故障平均时长${duration}小时(${durationAvg}天),环比解决时长${durationQoq}。数量(条)占比上月占比情况环比变化1次处理${oneHandle.total?c}${oneHandle.proportion}${oneHandle.lastProportion}${oneHandle.qoqTable}2次处理${twoHandle.total}${twoHandle.proportion}${twoHandle.lastProportion}${twoHandle.qoqTable}3次及以上处理${threeHandle.total}${threeHandle.proportion}${threeHandle.lastProportion}${threeHandle.qoqTable}合计${handleTotal?c}///工作要求请众望通高度重视运维工作,组织人力重点对“3次及以上处理”才能解决的故障作分析,提高解决故障效率。市局已要求各单位统一使用系统进行报障,非特殊情况不接受通过电话、QQ、微信等途径报障。请众望通集中人力处理系统的运维工作。下一步工作计划市局将汇总各区局相关总结和改进建议,定期召开系统运维情况沟通协调会,对系统运维情况进行通报,并完善系统日常监测机制,加强对系统运行情况的监测管理,力争有效缩短报障处理时长,确保系统办理许可登记业务的稳定性。佛山市市场监督管理局 ${currYear?c}年${currMonth}月${currDay}日 (联系人:______,联系电话:______)- PAGE \* MERGEFORMAT 1 - \ No newline at end of file diff --git a/src/test/java/com/chinaweal/youfool/devops/AppTest.java b/src/test/java/com/chinaweal/youfool/devops/AppTest.java new file mode 100644 index 0000000..a557de6 --- /dev/null +++ b/src/test/java/com/chinaweal/youfool/devops/AppTest.java @@ -0,0 +1,19 @@ +package com.chinaweal.youfool.devops; + +import com.chinaweal.youfool.framework.springboot.util.SM3Util; +import org.junit.Test; + +//@RunWith(SpringRunner.class) +//@SpringBootTest(classes = {YoufoolPmsApplication.class}) +public class AppTest { + + @Test + public void test1() { + String no = String.format("%04d", 51); + System.out.println(no); + System.out.println("12345678"); + + String encrypt = SM3Util.encrypt("82b0832fdaac473b83225ab92e7e3c3d", "123456"); + System.out.println(encrypt); + } +}