夏文涛 1 rok temu
rodzic
commit
90d3a77dab
100 zmienionych plików z 6439 dodań i 1 usunięć
  1. 21 0
      .gitignore
  2. 120 1
      README.md
  3. 53 0
      applications/admin-server/pom.xml
  4. 13 0
      applications/admin-server/src/main/java/com/flyhigh/adminserver/AdminServerApplication.java
  5. 41 0
      applications/admin-server/src/main/java/com/flyhigh/adminserver/config/AdminSecurityConfig.java
  6. 3 0
      applications/admin-server/src/main/resources/application.properties
  7. 36 0
      applications/patrol/README.md
  8. 1059 0
      applications/patrol/patrol-app/api/patrol-app_1.0.0.api
  9. 200 0
      applications/patrol/patrol-app/api/patrol-app_1.0.1.api
  10. 299 0
      applications/patrol/patrol-app/api/patrol-app_1.0.2.api
  11. 61 0
      applications/patrol/patrol-app/api/patrol-app_1.0.3.api
  12. 20 0
      applications/patrol/patrol-app/apidoc.json
  13. 5 0
      applications/patrol/patrol-app/apidoc_header.md
  14. 109 0
      applications/patrol/patrol-app/pom.xml
  15. 19 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/PatrolAppApplication.java
  16. 91 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/aspect/SysLogAspect.java
  17. 148 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/config/AppConstant.java
  18. 37 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/config/AppProperties.java
  19. 47 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/config/CaptchaConfig.java
  20. 40 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/controller/checkroute/CheckRouteExtController.java
  21. 72 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/controller/common/FileController.java
  22. 52 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/controller/device/DeviceBuildingExtController.java
  23. 43 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/controller/device/DeviceExtController.java
  24. 41 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/controller/device/DeviceFloorExtController.java
  25. 75 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/controller/device/DeviceRoomExtController.java
  26. 174 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/controller/patrol/PatrolTaskExtController.java
  27. 39 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/controller/system/SystemUserCommentExtController.java
  28. 108 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/controller/system/SystemUserExtController.java
  29. 170 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/controller/temporarytask/TemporaryTaskExtController.java
  30. 39 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/controller/temporarytask/TemporaryTaskFeedbackExtController.java
  31. 58 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/controller/visitor/VisitorAuditExtController.java
  32. 32 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/controller/visitor/VisitorRegulationExtController.java
  33. 30 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/controller/wechat/WechatController.java
  34. 32 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/entity/PageInfo.java
  35. 42 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/entity/Result.java
  36. 24 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/from/PatrolTaskRecordItemFrom.java
  37. 33 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/from/PatrolTaskRecordUpdateFrom.java
  38. 43 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/from/SystemUserCommentAddFrom.java
  39. 23 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/from/SystemUserLoginFrom.java
  40. 24 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/from/SystemUserPasswordUpdateFrom.java
  41. 68 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/from/TemporaryTaskAddFrom.java
  42. 27 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/from/TemporaryTaskFeedbackAddFrom.java
  43. 30 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/from/TemporaryTaskStatusUpdateFrom.java
  44. 70 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/from/VisitorAuditAddFrom.java
  45. 22 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/from/VisitorAuditUpdateFrom.java
  46. 25 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/checkroute/CheckRouteExtService.java
  47. 68 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/common/FileService.java
  48. 25 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/device/DeviceBuildingExtService.java
  49. 27 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/device/DeviceExtService.java
  50. 25 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/device/DeviceFloorExtService.java
  51. 56 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/device/DeviceRoomExtService.java
  52. 36 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/checkitem/CheckItemExtMapper.java
  53. 9 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/checkitem/CheckItemTypeExtMapper.java
  54. 35 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/checkroute/CheckRouteExtMapper.java
  55. 9 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/device/DeviceAndCheckItemExtMapper.java
  56. 29 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/device/DeviceBuildingExtMapper.java
  57. 9 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/device/DeviceCabinetChildDeviceExtMapper.java
  58. 9 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/device/DeviceCabinetLogExtMapper.java
  59. 65 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/device/DeviceExtMapper.java
  60. 9 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/device/DeviceExtraOfCabinetExtMapper.java
  61. 34 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/device/DeviceFloorExtMapper.java
  62. 9 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/device/DeviceRoomAndCheckItemExtMapper.java
  63. 84 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/device/DeviceRoomExtMapper.java
  64. 9 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/device/DeviceTemplateExtMapper.java
  65. 9 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/patrol/PatrolPlanAndSystemUserExtMapper.java
  66. 9 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/patrol/PatrolPlanExtMapper.java
  67. 9 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/patrol/PatrolTaskAndSystemUserExtMapper.java
  68. 430 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/patrol/PatrolTaskExtMapper.java
  69. 111 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/patrol/PatrolTaskRecordExtMapper.java
  70. 9 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/stock/StockChangeRecordExtMapper.java
  71. 9 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/stock/StockClassifyExtMapper.java
  72. 9 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/stock/StockGoodsExtMapper.java
  73. 9 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/system/SystemAttendanceExtMapper.java
  74. 9 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/system/SystemDatabaseBackupExtMapper.java
  75. 9 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/system/SystemDeptExtMapper.java
  76. 9 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/system/SystemElectricityExtMapper.java
  77. 9 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/system/SystemLogExtMapper.java
  78. 9 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/system/SystemLoginLogExtMapper.java
  79. 9 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/system/SystemPermissionsExtMapper.java
  80. 9 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/system/SystemRoleExtMapper.java
  81. 9 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/system/SystemUserCommentExtMapper.java
  82. 69 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/system/SystemUserExtMapper.java
  83. 9 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/temporarytask/TemporaryTaskAndSystemUserExtMapper.java
  84. 153 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/temporarytask/TemporaryTaskExtMapper.java
  85. 9 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/temporarytask/TemporaryTaskFeedbackExtMapper.java
  86. 9 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/upkeep/UpkeepPlanExtMapper.java
  87. 9 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/upkeep/UpkeepTaskExtMapper.java
  88. 9 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/visitor/VisitorAuditExtMapper.java
  89. 9 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/visitor/VisitorBackupExtMapper.java
  90. 9 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/visitor/VisitorRegulationExtMapper.java
  91. 448 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/patrol/PatrolTaskExtService.java
  92. 37 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/system/SystemUserCommentExtService.java
  93. 153 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/system/SystemUserExtService.java
  94. 212 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/temporarytask/TemporaryTaskExtService.java
  95. 46 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/temporarytask/TemporaryTaskFeedbackExtService.java
  96. 134 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/visitor/VisitorAuditExtService.java
  97. 23 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/visitor/VisitorRegulationExtService.java
  98. 37 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/util/wechat/WeChatUtil.java
  99. 23 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/vo/CheckItemNumDetailsVO.java
  100. 0 0
      applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/vo/CheckItemOptionVO.java

+ 21 - 0
.gitignore

@@ -0,0 +1,21 @@
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+*.iml
+
+### IntelliJ IDEA ###
+.idea
+
+
+logs
+/media
+/mysql
+
+/applications/**/lucene/
+/applications/**/views/
+/applications/**/src/main/java/**/model/
+/applications/**/src/main/java/**/dao/
+/applications/**/src/main/java/**/generate/
+/applications/**/src/main/resources/static/doc/
+/applications/**/temp/

+ 120 - 1
README.md

@@ -1 +1,120 @@
-# xunjian_houtai
+###请求流程
+
+    https://blog.csdn.net/sinat_41620463/article/details/89311485
+
+    Filter -> doService -> doDispatch -> Handler
+                                         /    \
+                                        /      \
+                                       /        \
+                                      /          \
+                                     /            \
+                             ResourceHandler  MappingHandler
+                                    |              |
+                             Static Resource   Interceptor
+                                                   |
+                                             ControllerAdvice
+                                                   |
+                                                Aspect
+                                                   |
+                                               Controller
+
+###spring boot DevTools 配置
+#### 1、pox.xml
+    <dependency>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-devtools</artifactId>
+        <optional>true</optional>
+        <!-- optional目的是为了继承他的项目不继承这个devtools插件        -->
+    </dependency>
+    <build>
+        <plugins>
+            <plugin>
+                <!--热部署配置-->
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <!--fork:如果没有该项配置,整个devtools不会起作用(根据个人情况而定,最好加上)-->
+                    <fork>true</fork>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+#### 2、勾选Build project automatically(自动构建)
+    settings -> build, Execution, Deployment -> Compiler -> 勾选 Build project automatically
+#### 3、设置自动加载资源配置和编译
+    Run/Debug Configurations -> Running Application Update Policies ->
+        On 'Update' action: Update classes and resources
+        On frame deactivation: Update classes and resources
+
+### 表注释,可以根据注释选择性的生成一些基本Controller
+    name:应用名称,会过滤掉与工程名不一致的表
+    group:一级菜单-二级菜单
+    prefix:表前缀(一级菜单)
+    remarks:表注释
+    version:生成接口版本
+    ext:是否生成扩展Controller文件
+    add:插入
+    remove:根据id删除一个
+    removes:根据ids删除多个
+    update:根据id更新
+    query:查询一个
+    queries:查询列表,带排序
+    例:
+    [
+        {
+            "name": "app",
+            "group": "系统设置-权限管理",
+            "prefix": "system",
+            "remarks": "权限",
+            "version": "1.0.0",
+            "ext": true/1,
+            "add": true/1,
+            "remove": true/1,
+            "removes": false/0,
+            "update": false/0,
+            "query": false/0,
+            "queries": false/0,
+        }
+    ]
+
+### apidoc安装
+
+    npm install -g apidoc
+    插件修改(支持中文分组)
+        注释掉 用户目录\AppData\Roaming\npm\node_modules\apidoc\lib\core\workers\api_grop.js 中的 group = group.replace(/^[^a-z]+|[^\w:.-]+/gi, '');
+
+### 生成api文档
+    Plugins -> apidoc
+
+### 清理数据库
+
+    SET FOREIGN_KEY_CHECKS=0;
+    truncate table system_permissions;
+    truncate table system_role_and_permissions;
+    truncate table system_log;
+    truncate table system_login_log;
+    SET FOREIGN_KEY_CHECKS=1;
+
+### 权限初始化
+    生成api文件时会生成 permissions.json 文件
+    运行项目时会根据 permissions 文件初始化 super_admin 权限
+
+### 添加项目流程
+    1、新建项目模块
+    2、参考template/app-base模块中的pom.xml修改新项目的pom文件,一般复制后仅需修改项目名称
+    3、同步maven工程
+    4、新建项目数据库,导入 app_base.sql
+    5、复制app-base模块中的资源文件
+        修改资源中配置文件 application-dev.properties、application-prod.properties、application-test.properties
+            主要修改数据库地址、账号、密码, redis主机地址、账号、密码
+    6、复制app-base模块中的源码文件
+        注意修改application中的scanBasePackages,添加本模块包名
+        将新模块中的 com.flyhigh.app 全部替换为 新模块包名
+        ### 代码提交至多个仓库
+
+### 项目推送至多个仓库
+    1、给origin添加一个远程push地址,这样一次push就能同时push到两个地址上面
+        git remote set-url --add origin 地址
+        git remote -v //查看是否多了一条push地址(可不执行)
+    2、推送
+        git push origin master -f // 如果第一次推不上去代码,可以使用强推的方式

+ 53 - 0
applications/admin-server/pom.xml

@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>applications</artifactId>
+        <groupId>com.flyhigh</groupId>
+        <version>1.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>admin-server</artifactId>
+    <name>admin-server</name>
+    <version>1.0.0</version>
+    <packaging>jar</packaging>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <!-- https://mvnrepository.com/artifact/de.codecentric/spring-boot-admin-starter-server -->
+        <dependency>
+            <groupId>de.codecentric</groupId>
+            <artifactId>spring-boot-admin-starter-server</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-security</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <!-- 工程清理插件 -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-clean-plugin</artifactId>
+            </plugin>
+
+            <plugin>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <groupId>org.springframework.boot</groupId>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 13 - 0
applications/admin-server/src/main/java/com/flyhigh/adminserver/AdminServerApplication.java

@@ -0,0 +1,13 @@
+package com.flyhigh.adminserver;
+
+import de.codecentric.boot.admin.server.config.EnableAdminServer;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@EnableAdminServer
+@SpringBootApplication
+public class AdminServerApplication {
+    public static void main(String[] args) {
+        SpringApplication.run(AdminServerApplication.class, args);
+    }
+}

+ 41 - 0
applications/admin-server/src/main/java/com/flyhigh/adminserver/config/AdminSecurityConfig.java

@@ -0,0 +1,41 @@
+package com.flyhigh.adminserver.config;
+
+import de.codecentric.boot.admin.server.config.AdminServerProperties;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
+import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
+
+@Configuration(proxyBeanMethods = false)
+public class AdminSecurityConfig extends WebSecurityConfigurerAdapter {
+
+    private final String adminContextPath;
+
+    public AdminSecurityConfig(AdminServerProperties adminServerProperties) {
+        this.adminContextPath = adminServerProperties.getContextPath();
+    }
+
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
+        successHandler.setTargetUrlParameter("redirectTo");
+        successHandler.setDefaultTargetUrl(adminContextPath + "/");
+
+        http.authorizeRequests()
+                .antMatchers(adminContextPath + "/assets/**").permitAll()
+                .antMatchers(adminContextPath + "/login").permitAll()
+                .antMatchers(adminContextPath + "/instances/**").permitAll()
+                .anyRequest().authenticated()
+                .and()
+                .formLogin().loginPage(adminContextPath + "/login").successHandler(successHandler).and()
+                .logout().logoutUrl(adminContextPath + "/logout").and()
+                .httpBasic().and()
+                .csrf()
+                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
+                .ignoringAntMatchers(
+                        adminContextPath + "/instances",
+                        adminContextPath + "/actuator/**"
+                );
+    }
+}

+ 3 - 0
applications/admin-server/src/main/resources/application.properties

@@ -0,0 +1,3 @@
+server.port=23333
+spring.security.user.name=flyhigh2016
+spring.security.user.password=flyhigh_2016

+ 36 - 0
applications/patrol/README.md

@@ -0,0 +1,36 @@
+### 原型文档
+	https://www.xiaopiu.com/h5/byId?type=project&id=5f27b558fd472f065fa78755&activePage=48
+	https://www.xiaopiu.com/web/byId?type=project&id=621682d471fb6525a3651b9a
+
+### 服务器配置
+	centos 7.9
+	域名:https://smartjingan.xyz
+	账号密码:root Jingan2018
+	IP: 47.101.178.90 
+	配置:1核 16G
+
+### Mysql账号
+	username: root
+	password: Chuanghai_2018
+	address: 47.101.178.90
+	port: 3306
+
+### 管理端环境
+	node版本 v16.13.2
+	npm版本 8.1.2
+	安装依赖 npm install
+	运行项目 npm run serve
+	编译项目 npm run build
+	部署服务器位置 /usr/local/myproject/patrol/manage-web2
+	管理端访问地址 https://smartjingan.xyz/patrolWeb2
+	api文档地址 https://smartjingan.xyz/patrolWeb2/doc/api
+
+### 服务端环境
+	nginx版本 1.18.0   /usr/local/nginx
+	mysql版本 8.0.26   /usr/local/mysql
+	redis版本 2.8.19   /usr/local/redis
+	开发工具IntelliJ IDEA 2021.3.2
+	管理端部署服务器位置 /usr/local/myproject/patrol/web
+	小程序端部署服务器位置 /usr/local/myproject/patrol/app
+	数据库模型 patrol.ndm2
+	数据库初始化脚本 patrol.sql

Plik diff jest za duży
+ 1059 - 0
applications/patrol/patrol-app/api/patrol-app_1.0.0.api


+ 200 - 0
applications/patrol/patrol-app/api/patrol-app_1.0.1.api

@@ -0,0 +1,200 @@
+/**
+ * @api {post} /v1/system/user/login 01.登录
+ * @apiName 登录
+ * @apiGroup 用户
+ * @apiHeader {String =  application/json} Content-Type = application/json
+ * @apiHeader {String = zh-CN,en-US } accept-language = zh-CN
+ * @apiVersion 1.0.1
+ * @apiBody { String } username 用户名
+ * @apiBody { String } password 用户密码(md5加密)
+ * @apiSuccess { Object } data 数据
+ * @apiSuccess { Long } data.id 用户id
+ * @apiSuccess { String } data.username 用户名称
+ * @apiSuccess { String } data.telephone 手机号
+ * @apiSuccess { String } data.deptName 用户部门
+ * @apiSuccess { String } data.token 授权信息
+ * @apiSuccess { String } message 信息
+ * @apiSuccess { Integer } code 状态码
+ * @apiSuccessExample Response
+ *
+ * {"data":{"id":1, "username":"", "telephone":"", "deptName":"", "token":""}, "message":"", "code":1}
+ */
+
+/**
+ * @api {get} /v1/patrol/task/list 01.巡检计划
+ * @apiName 巡检计划
+ * @apiGroup 巡检任务
+ * @apiHeader {String =  application/x-www-form-urlencoded} Content-Type = application/x-www-form-urlencoded
+ * @apiHeader {String = zh-CN,en-US } accept-language = zh-CN
+ * @apiHeader {String} Authorization 授权信息
+ * @apiVersion 1.0.1
+ * @apiQuery { Integer } [ status ] 检查状态 1未开始、2进行中、3正常完成、4超时漏检、5超时完成
+ * @apiQuery { Date } [ beginTimeStart ] 任务执行开始时间 开始时间
+ * @apiQuery { Date } [ beginTimeEnd ] 任务执行开始时间 结束时间
+ * @apiQuery { Integer } [ page = 1 ] 页码
+ * @apiQuery { Integer } [ size = 10 ] 页大小
+ * @apiQuery { String { ^[-+][\w]+ } } [ order = -id ] 排序规则(默认ID倒序),排序字段前加:+表示正序 -表示倒序
+ * @apiSuccess { Object } data 数据
+ * @apiSuccess { Long } data.total 数据总数
+ * @apiSuccess { Object[] } data.list 数据列表
+ * @apiSuccess { Long } data.list.id id 主键
+ * @apiSuccess { String } data.list.name 名称
+ * @apiSuccess { Date } data.list.beginTime 任务执行开始时间
+ * @apiSuccess { Date } data.list.endTime 任务执行结束时间
+ * @apiSuccess { Integer } data.list.status 状态 1未开始、2进行中、3正常完成、4超时漏检、5超时完成
+ * @apiSuccess { Integer } data.list.total 计划巡检房间数
+ * @apiSuccess { Integer } data.list.completed 已经完成房间数
+ * @apiSuccess { Float } data.list.completionRate 完成率
+ * @apiSuccess { String } message 信息
+ * @apiSuccess { Integer } code 状态码
+ * @apiSuccessExample Response
+ *
+ * {"data":{"total":1, "list":[{"id":1, "name":"", "beginTime":1651827836584, "endTime":1651827836584, "status":1, "total":1, "completed":1, "completionRate":1.0}]}, "message":"", "code":1}
+ * {"data":{"total":1, "list":[{"id":1, "name":"", "beginTime":1651835636006, "endTime":1651835636006, "status":1, "total":1, "completed":1, "completionRate":1.0}]}, "message":"", "code":1}
+ */
+
+/**
+ * @api {get} /v1/patrol/task/list/room 02.选择计划
+ * @apiName 选择计划
+ * @apiGroup 巡检任务
+ * @apiHeader {String =  application/x-www-form-urlencoded} Content-Type = application/x-www-form-urlencoded
+ * @apiHeader {String = zh-CN,en-US } accept-language = zh-CN
+ * @apiHeader {String} Authorization 授权信息
+ * @apiVersion 1.0.1
+ * @apiQuery { Long } roomId 房间id
+ * @apiSuccess { Object[] } data 数据
+ * @apiSuccess { Long } data.id id 主键
+ * @apiSuccess { String } data.name 名称
+ * @apiSuccess { Date } data.beginTime 任务执行开始时间
+ * @apiSuccess { Date } data.endTime 任务执行结束时间
+ * @apiSuccess { Integer } data.status 状态 1未开始、2进行中、3正常完成、4超时漏检、5超时完成
+ * @apiSuccess { Integer } data.total 计划巡检房间数
+ * @apiSuccess { Integer } data.completed 已经完成房间数
+ * @apiSuccess { Float } data.completionRate 完成率
+ * @apiSuccess { String } message 信息
+ * @apiSuccess { Integer } code 状态码
+ * @apiSuccessExample Response
+ *
+ * {"data":[{"id":1, "name":"", "beginTime":1651827836584, "endTime":1651827836584, "status":1, "total":1, "completed":1, "completionRate":1.0}], "message":"", "code":1}
+ * {"data":[{"id":1, "name":"", "beginTime":1651835636006, "endTime":1651835636006, "status":1, "total":1, "completed":1, "completionRate":1.0}], "message":"", "code":1}
+ */
+
+/**
+ * @api {get} /v1/patrol/task/query/rate/:id 03.巡检进度
+ * @apiName 巡检进度
+ * @apiGroup 巡检任务
+ * @apiHeader {String =  application/x-www-form-urlencoded} Content-Type = application/x-www-form-urlencoded
+ * @apiHeader {String = zh-CN,en-US } accept-language = zh-CN
+ * @apiHeader {String} Authorization 授权信息
+ * @apiVersion 1.0.1
+ * @apiParam { Long } id 巡检任务id
+ * @apiSuccess { Object } data 数据
+ * @apiSuccess { Long } data.id id 主键
+ * @apiSuccess { String } data.name 名称
+ * @apiSuccess { Date } data.beginTime 任务执行开始时间
+ * @apiSuccess { Date } data.endTime 任务执行结束时间
+ * @apiSuccess { Integer } data.total 计划巡检房间数
+ * @apiSuccess { Integer } data.completed 已经完成房间数
+ * @apiSuccess { Float } data.completionRate 完成率
+ * @apiSuccess { Object[] } data.rooms 房间列表
+ * @apiSuccess { Long } data.rooms.id 房间id
+ * @apiSuccess { String } data.rooms.name 房间名称
+ * @apiSuccess { String } data.rooms.number 房间编号
+ * @apiSuccess { Boolean } data.rooms.qualified 是否合格
+ * @apiSuccess { Boolean } data.rooms.completed 是否已巡检
+ * @apiSuccess { String } message 信息
+ * @apiSuccess { Integer } code 状态码
+ * @apiSuccessExample Response
+ *
+ * {"data":{"id":1, "name":"", "beginTime":1651827836584, "endTime":1651827836584, "total":1, "completed":1, "completionRate":1.0, "rooms":[{"id":1, "name":"", "number":"", "qualified":true, "completed":true}]}, "message":"", "code":1}
+ * {"data":{"id":1, "name":"", "beginTime":1651835636006, "endTime":1651835636006, "total":1, "completed":1, "completionRate":1.0, "rooms":[{"id":1, "name":"", "number":"", "qualified":true, "completed":true}]}, "message":"", "code":1}
+ */
+
+/**
+ * @api {get} /v1/visitor/regulation/query 01.查询制度
+ * @apiName 查询制度
+ * @apiGroup 制度管理
+ * @apiHeader {String =  application/x-www-form-urlencoded} Content-Type = application/x-www-form-urlencoded
+ * @apiHeader {String = zh-CN,en-US } accept-language = zh-CN
+ * @apiVersion 1.0.1
+ * @apiSuccess { Object } data 数据
+ * @apiSuccess { Long } data.id id主键
+ * @apiSuccess { Long } data.userId 编辑用户id
+ * @apiSuccess { String } data.username 编辑用户名称
+ * @apiSuccess { Date } data.createTime 创建时间
+ * @apiSuccess { Date } data.updateTime 更新时间
+ * @apiSuccess { String } data.content 内容
+ * @apiSuccess { String } message 信息
+ * @apiSuccess { Integer } code 状态码
+ * @apiSuccessExample Response
+ *
+ * {"data":{"id":1, "userId":1, "username":"", "createTime":1651827836584, "updateTime":1651827836584, "content":""}, "message":"", "code":1}
+ * {"data":{"id":1, "userId":1, "username":"", "createTime":1651835636007, "updateTime":1651835636007, "content":""}, "message":"", "code":1}
+ */
+
+/**
+ * @api {post} /v1/visitor/audit/add 01.进入登记
+ * @apiName 进入登记
+ * @apiGroup 访客审批
+ * @apiHeader {String =  application/json} Content-Type = application/json
+ * @apiHeader {String = zh-CN,en-US } accept-language = zh-CN
+ * @apiVersion 1.0.1
+ * @apiBody { String } openid 用户openid
+ * @apiBody { String } username 访客姓名
+ * @apiBody { String } userPhone 访客手机号
+ * @apiBody { String } company 访客公司
+ * @apiBody { Integer } duration 访问时长(小时)
+ * @apiBody { String } [ itineraryCode ] 行程码
+ * @apiBody { String } [ healthCode ] 健康码
+ * @apiBody { Boolean } [ highRisk ] 是否高风险
+ * @apiBody { String } reason 事由
+ * @apiBody { String } [ information ] 审核资料
+ * @apiSuccess { Boolean } data 数据
+ * @apiSuccess { String } message 信息
+ * @apiSuccess { Integer } code 状态码
+ * @apiSuccessExample Response
+ *
+ * {"data":true, "message":"", "code":1}
+ */
+
+/**
+ * @api {get} /v1/visitor/audit/query/:openid 02.查询进入记录
+ * @apiName 查询进入记录
+ * @apiGroup 访客审批
+ * @apiHeader {String =  application/x-www-form-urlencoded} Content-Type = application/x-www-form-urlencoded
+ * @apiHeader {String = zh-CN,en-US } accept-language = zh-CN
+ * @apiVersion 1.0.1
+ * @apiParam { String } openid 用户openid
+ * @apiSuccess { Object } data 数据
+ * @apiSuccess { Long } data.id id主键
+ * @apiSuccess { String } data.openid 用户openid
+ * @apiSuccess { String } data.username 访客姓名
+ * @apiSuccess { String } data.userPhone 访客手机号
+ * @apiSuccess { String } data.company 访客公司
+ * @apiSuccess { Date } data.entryTime 进入时间
+ * @apiSuccess { String } data.reason 事由
+ * @apiSuccess { String } message 信息
+ * @apiSuccess { Integer } code 状态码
+ * @apiSuccessExample Response
+ *
+ * {"data":{"id":1, "openid":"", "username":"", "userPhone":"", "company":"", "entryTime":1651827836584, "reason":""}, "message":"", "code":1}
+ * {"data":{"id":1, "openid":"", "username":"", "userPhone":"", "company":"", "entryTime":1651835636007, "reason":""}, "message":"", "code":1}
+ */
+
+/**
+ * @api {put} /v1/visitor/audit/update 03.出场核销
+ * @apiName 出场核销
+ * @apiGroup 访客审批
+ * @apiHeader {String =  application/json} Content-Type = application/json
+ * @apiHeader {String = zh-CN,en-US } accept-language = zh-CN
+ * @apiVersion 1.0.1
+ * @apiBody { Long } id 入场记录id
+ * @apiBody { String } [ remark ] 出场备注
+ * @apiSuccess { Boolean } data 数据
+ * @apiSuccess { String } message 信息
+ * @apiSuccess { Integer } code 状态码
+ * @apiSuccessExample Response
+ *
+ * {"data":true, "message":"", "code":1}
+ */
+

+ 299 - 0
applications/patrol/patrol-app/api/patrol-app_1.0.2.api

@@ -0,0 +1,299 @@
+
+/**
+ * @api {post} /v1/temporary/task/add 01.添加临时任务
+ * @apiName 添加临时任务
+ * @apiGroup 临时任务
+ * @apiVersion 1.0.2
+ * @apiHeader {String = application/json} Content-Type = application/json
+ * @apiHeader {String} Authorization = eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX3V1aWQiOjQzMTI2MzMxODcxMjE5NzEyLCJuYmYiOjE2NDkzMDQ1ODZ9.FvG8hY0R6D9lO1t4GR1bDhQVayGU5gHVCcy0SIX1r0c 授权信息
+ * @apiHeader {String = zh-CN,en-US} accept-language = zh-CN
+ * @apiBody { String { 0..255 } } title 任务标题
+ * @apiBody { Long } roomId 房间id
+ * @apiBody { String } belongSystem 所属系统
+ * @apiBody { Integer } type 任务类型  1:一般任务 2: 较急任务 3:紧急任务
+ * @apiBody { String { 0..255 } } content 任务内容
+ * @apiBody { Long[] } executors 执行人列表
+ * @apiBody { Date } finishTime 完成时间
+ * @apiBody { String } [ images ] 任务图片
+ * @apiSuccess { Object } data 数据
+ * @apiSuccess { Long } data.id 任务id
+ * @apiSuccess { Long } data.roomId 房间id
+ * @apiSuccess { String } data.belongSystem 所属系统
+ * @apiSuccess { String } data.title 任务标题
+ * @apiSuccess { Integer } data.type 任务类型  1:般任务 2:较急任务 3:紧急任务
+ * @apiSuccess { String } data.content 任务内容
+ * @apiSuccess { Long } data.userId 任务创建用户id
+ * @apiSuccess { Integer } data.status 任务状态 1:正在处理 2:已经完成 3:已经取消 4:超时任务
+ * @apiSuccess { Integer } data.auditStatus 审核状态 1:未提交 2:待审核 3:不通过
+ * @apiSuccess { String } data.remark 审核备注
+ * @apiSuccess { Integer } data.feedbackTotal 任务反馈数量
+ * @apiSuccess { Date } data.publishTime 任务发布时间
+ * @apiSuccess { Date } data.finishTime 任务完成时间
+ * @apiSuccess { String } data.images 任务图片
+ * @apiSuccess { String } message 信息
+ * @apiSuccess { Integer } code 状态码
+ * @apiSuccessExample Response
+ *
+ * {"data":{"id":1, "roomId":1, "belongSystem":"", "title":"", "type":1, "content":"", "userId":1, "status":1, "auditStatus":1, "remark":"", "feedbackTotal":1, "publishTime":1653458692071, "finishTime":1653458692071, "images":""}, "message":"", "code":1}
+ */
+
+/**
+ * @api {put} /v1/temporary/task/update 02.更新临时任务
+ * @apiName 更新临时任务
+ * @apiGroup 临时任务
+ * @apiVersion 1.0.2
+ * @apiHeader {String = application/json} Content-Type = application/json
+ * @apiHeader {String} Authorization = eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX3V1aWQiOjQzMTI2MzMxODcxMjE5NzEyLCJuYmYiOjE2NDkzMDQ1ODZ9.FvG8hY0R6D9lO1t4GR1bDhQVayGU5gHVCcy0SIX1r0c 授权信息
+ * @apiHeader {String = zh-CN,en-US} accept-language = zh-CN
+ * @apiBody { Long } id id 主键
+ * @apiBody { Integer } status 任务状态 1:完成 2:取消 3:不通过
+ * @apiBody { String } [ remake ] 审核备注
+ * @apiSuccess { Object } data 数据
+ * @apiSuccess { Long } data.id 任务id
+ * @apiSuccess { Long } data.roomId 房间id
+ * @apiSuccess { String } data.belongSystem 所属系统
+ * @apiSuccess { String } data.title 任务标题
+ * @apiSuccess { Integer } data.type 任务类型  1:般任务 2:较急任务 3:紧急任务
+ * @apiSuccess { String } data.content 任务内容
+ * @apiSuccess { Long } data.userId 任务创建用户id
+ * @apiSuccess { Integer } data.status 任务状态 1:正在处理 2:已经完成 3:已经取消 4:超时任务
+ * @apiSuccess { Integer } data.auditStatus 审核状态 1:未提交 2:待审核 3:不通过
+ * @apiSuccess { String } data.remark 审核备注
+ * @apiSuccess { Integer } data.feedbackTotal 任务反馈数量
+ * @apiSuccess { Date } data.publishTime 任务发布时间
+ * @apiSuccess { Date } data.finishTime 任务完成时间
+ * @apiSuccess { String } data.images 任务图片
+ * @apiSuccess { String } message 信息
+ * @apiSuccess { Integer } code 状态码
+ * @apiSuccessExample Response
+ *
+ * {"data":{"id":1, "roomId":1, "belongSystem":"", "title":"", "type":1, "content":"", "userId":1, "status":1, "auditStatus":1, "remark":"", "feedbackTotal":1, "publishTime":1653458692071, "finishTime":1653458692071, "images":""}, "message":"", "code":1}
+ */
+
+/**
+ * @api {get} /v1/temporary/task/list 03.分页查询临时任务
+ * @apiName 分页查询临时任务
+ * @apiGroup 临时任务
+ * @apiVersion 1.0.2
+ * @apiHeader {String = application/x-www-form-urlencoded} Content-Type = application/x-www-form-urlencoded
+ * @apiHeader {String} Authorization = eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX3V1aWQiOjQzMTI2MzMxODcxMjE5NzEyLCJuYmYiOjE2NDkzMDQ1ODZ9.FvG8hY0R6D9lO1t4GR1bDhQVayGU5gHVCcy0SIX1r0c 授权信息
+ * @apiHeader {String = zh-CN,en-US} accept-language = zh-CN
+ * @apiQuery { String } [ title ] 任务标题
+ * @apiQuery { Integer } [ type ] 任务类型 1:一般任务 2: 较急任务 3:紧急任务
+ * @apiQuery { Integer } [ status ] 任务状态 1:正在处理 2:已经完成 3:已经取消 4:超时任务
+ * @apiQuery { Integer } [ auditStatus ] 审核状态 1:未提交 2:待审核 3:不通过
+ * @apiQuery { String } [ content ] 任务内容
+ * @apiQuery { String } [ username ] 发起人名称
+ * @apiQuery { String } [ executor ] 执行人名称
+ * @apiQuery { Date } [ startTime ] 开始日期
+ * @apiQuery { Date } [ endTime ] 结束日期
+ * @apiQuery { Integer } [ page = 1 ] 页码
+ * @apiQuery { Integer } [ size = 10 ] 页大小
+ * @apiQuery { String { ^[-+][\w]+ } } [ order = -id ] 排序规则(默认ID倒序),排序字段前加:+表示正序 -表示倒序
+ * @apiSuccess { Object } data 数据
+ * @apiSuccess { Long } data.total 数据总数
+ * @apiSuccess { Object[] } data.list 数据列表
+ * @apiSuccess { Long } data.list.id 任务id
+ * @apiSuccess { Long } data.list.roomId 房间id
+ * @apiSuccess { String } data.list.roomName 房间名称
+ * @apiSuccess { String } data.list.belongSystem 所属系统
+ * @apiSuccess { String } data.list.title 任务标题
+ * @apiSuccess { Integer } data.list.type 任务类型  1:一般任务 2: 较急任务 3:紧急任务
+ * @apiSuccess { String } data.list.username 发起人姓名
+ * @apiSuccess { Integer } data.list.status 任务状态 1:正在处理 2:已经完成 3:已经取消 4:超时任务
+ * @apiSuccess { Integer } data.list.auditStatus 审核状态 1:未提交 2:待审核 3:不通过
+ * @apiSuccess { String } data.list.remark 审核备注
+ * @apiSuccess { String } data.list.content 任务内容
+ * @apiSuccess { Integer } data.list.feedbackTotal 执行反馈次数
+ * @apiSuccess { Date } data.list.publishTime 发布时间
+ * @apiSuccess { Date } data.list.finishTime 完成时间
+ * @apiSuccess { String } data.list.images 任务图片
+ * @apiSuccess { String[] } data.list.executors 执行人
+ * @apiSuccess { String } message 信息
+ * @apiSuccess { Integer } code 状态码
+ * @apiSuccessExample Response
+ *
+ * {"data":{"total":1, "list":[{"id":1, "roomId":1, "roomName":"", "belongSystem":"", "title":"", "type":1, "username":"", "status":1, "auditStatus":1, "remark":"", "content":"", "feedbackTotal":1, "publishTime":1653458692071, "finishTime":1653458692071, "images":"", "executors":[""]}]}, "message":"", "code":1}
+ */
+
+/**
+ * @api {get} /v1/temporary/task/list/receive 05.我收到的临时任务列表
+ * @apiName 我收到的临时任务列表
+ * @apiGroup 临时任务
+ * @apiVersion 1.0.2
+ * @apiHeader {String = application/x-www-form-urlencoded} Content-Type = application/x-www-form-urlencoded
+ * @apiHeader {String} Authorization = eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX3V1aWQiOjQzMTI2MzMxODcxMjE5NzEyLCJuYmYiOjE2NDkzMDQ1ODZ9.FvG8hY0R6D9lO1t4GR1bDhQVayGU5gHVCcy0SIX1r0c 授权信息
+ * @apiHeader {String = zh-CN,en-US} accept-language = zh-CN
+ * @apiQuery { Integer } status 任务状态 1:正在处理 2:已经完成 3:已经取消 4:超时任务
+ * @apiQuery { Integer } [ page = 1 ]
+ * @apiQuery { Integer } [ size = 10 ]
+ * @apiQuery { String { ^[-+][\w]+ } } [ order = -id ]
+ * @apiSuccess { Object } data 数据
+ * @apiSuccess { Long } data.total 数据总数
+ * @apiSuccess { Object[] } data.list 数据列表
+ * @apiSuccess { Long } data.list.id 任务id
+ * @apiSuccess { Long } data.list.roomId 房间id
+ * @apiSuccess { String } data.list.roomName 房间名称
+ * @apiSuccess { String } data.list.belongSystem 所属系统
+ * @apiSuccess { String } data.list.title 任务标题
+ * @apiSuccess { Integer } data.list.type 任务类型  1:一般任务 2: 较急任务 3:紧急任务
+ * @apiSuccess { String } data.list.username 发起人姓名
+ * @apiSuccess { Integer } data.list.status 任务状态 1:正在处理 2:已经完成 3:已经取消 4:超时任务
+ * @apiSuccess { Integer } data.list.auditStatus 审核状态 1:未提交 2:待审核 3:不通过
+ * @apiSuccess { String } data.list.remark 审核备注
+ * @apiSuccess { String } data.list.content 任务内容
+ * @apiSuccess { Integer } data.list.feedbackTotal 执行反馈次数
+ * @apiSuccess { Date } data.list.publishTime 发布时间
+ * @apiSuccess { Date } data.list.finishTime 完成时间
+ * @apiSuccess { String } data.list.images 任务图片
+ * @apiSuccess { String[] } data.list.executors 执行人
+ * @apiSuccess { String } message 信息
+ * @apiSuccess { Integer } code 状态码
+ * @apiSuccessExample Response
+ *
+ * {"data":{"total":1, "list":[{"id":1, "roomId":1, "roomName":"", "belongSystem":"", "title":"", "type":1, "username":"", "status":1, "auditStatus":1, "remark":"", "content":"", "feedbackTotal":1, "publishTime":1653458692071, "finishTime":1653458692071, "images":"", "executors":[""]}]}, "message":"", "code":1}
+ */
+
+/**
+ * @api {get} /v1/temporary/task/list/publish 07.我发出的任务列表
+ * @apiName 我发出的任务列表
+ * @apiGroup 临时任务
+ * @apiVersion 1.0.2
+ * @apiHeader {String = application/x-www-form-urlencoded} Content-Type = application/x-www-form-urlencoded
+ * @apiHeader {String} Authorization = eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX3V1aWQiOjQzMTI2MzMxODcxMjE5NzEyLCJuYmYiOjE2NDkzMDQ1ODZ9.FvG8hY0R6D9lO1t4GR1bDhQVayGU5gHVCcy0SIX1r0c 授权信息
+ * @apiHeader {String = zh-CN,en-US} accept-language = zh-CN
+ * @apiQuery { Integer } status 任务状态 1:正在处理 2:已经完成 3:已经取消 4:超时任务
+ * @apiQuery { Integer } [ page = 1 ]
+ * @apiQuery { Integer } [ size = 10 ]
+ * @apiQuery { String { ^[-+][\w]+ } } [ order = -id ]
+ * @apiSuccess { Object } data 数据
+ * @apiSuccess { Long } data.total 数据总数
+ * @apiSuccess { Object[] } data.list 数据列表
+ * @apiSuccess { Long } data.list.id 任务id
+ * @apiSuccess { Long } data.list.roomId 房间id
+ * @apiSuccess { String } data.list.roomName 房间名称
+ * @apiSuccess { String } data.list.belongSystem 所属系统
+ * @apiSuccess { String } data.list.title 任务标题
+ * @apiSuccess { Integer } data.list.type 任务类型  1:一般任务 2: 较急任务 3:紧急任务
+ * @apiSuccess { String } data.list.username 发起人姓名
+ * @apiSuccess { Integer } data.list.status 任务状态 1:正在处理 2:已经完成 3:已经取消 4:超时任务
+ * @apiSuccess { Integer } data.list.auditStatus 审核状态 1:未提交 2:待审核 3:不通过
+ * @apiSuccess { String } data.list.remark 审核备注
+ * @apiSuccess { String } data.list.content 任务内容
+ * @apiSuccess { Integer } data.list.feedbackTotal 执行反馈次数
+ * @apiSuccess { Date } data.list.publishTime 发布时间
+ * @apiSuccess { Date } data.list.finishTime 完成时间
+ * @apiSuccess { String } data.list.images 任务图片
+ * @apiSuccess { String[] } data.list.executors 执行人
+ * @apiSuccess { String } message 信息
+ * @apiSuccess { Integer } code 状态码
+ * @apiSuccessExample Response
+ *
+ * {"data":{"total":1, "list":[{"id":1, "roomId":1, "roomName":"", "belongSystem":"", "title":"", "type":1, "username":"", "status":1, "auditStatus":1, "remark":"", "content":"", "feedbackTotal":1, "publishTime":1653458692071, "finishTime":1653458692072, "images":"", "executors":[""]}]}, "message":"", "code":1}
+ */
+
+/**
+ * @api {get} /v1/temporary/task/query/newest 08.我收到的最新的一条任务
+ * @apiName 我收到的最新的一条任务
+ * @apiGroup 临时任务
+ * @apiVersion 1.0.2
+ * @apiHeader {String = application/x-www-form-urlencoded} Content-Type = application/x-www-form-urlencoded
+ * @apiHeader {String} Authorization = eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX3V1aWQiOjQzMTI2MzMxODcxMjE5NzEyLCJuYmYiOjE2NDkzMDQ1ODZ9.FvG8hY0R6D9lO1t4GR1bDhQVayGU5gHVCcy0SIX1r0c 授权信息
+ * @apiHeader {String = zh-CN,en-US} accept-language = zh-CN
+ * @apiQuery { Integer } [ status ] 任务状态 1:正在处理 2:已经完成 3:已经取消 4:超时任务 不传时查询所有任务
+ * @apiSuccess { Object } data 数据
+ * @apiSuccess { Long } data.id 任务id
+ * @apiSuccess { Long } data.roomId 房间id
+ * @apiSuccess { String } data.roomName 房间名称
+ * @apiSuccess { String } data.belongSystem 所属系统
+ * @apiSuccess { String } data.title 任务标题
+ * @apiSuccess { Integer } data.type 任务类型  1:一般任务 2: 较急任务 3:紧急任务
+ * @apiSuccess { String } data.username 发起人姓名
+ * @apiSuccess { Integer } data.status 任务状态 1:正在处理 2:已经完成 3:已经取消 4:超时任务
+ * @apiSuccess { Integer } data.auditStatus 审核状态 1:未提交 2:待审核 3:不通过
+ * @apiSuccess { String } data.remark 审核备注
+ * @apiSuccess { String } data.content 任务内容
+ * @apiSuccess { Integer } data.feedbackTotal 执行反馈次数
+ * @apiSuccess { Date } data.publishTime 发布时间
+ * @apiSuccess { Date } data.finishTime 完成时间
+ * @apiSuccess { String } data.images 任务图片
+ * @apiSuccess { String[] } data.executors 执行人
+ * @apiSuccess { String } message 信息
+ * @apiSuccess { Integer } code 状态码
+ * @apiSuccessExample Response
+ *
+ * {"data":{"id":1, "roomId":1, "roomName":"", "belongSystem":"", "title":"", "type":1, "username":"", "status":1, "auditStatus":1, "remark":"", "content":"", "feedbackTotal":1, "publishTime":1653458692072, "finishTime":1653458692072, "images":"", "executors":[""]}, "message":"", "code":1}
+ */
+
+/**
+ * @api {get} /v1/patrol/task/list/record 09.巡检记录
+ * @apiName 巡检记录
+ * @apiGroup 巡检任务
+ * @apiVersion 1.0.2
+ * @apiHeader {String = application/x-www-form-urlencoded} Content-Type = application/x-www-form-urlencoded
+ * @apiHeader {String} Authorization = eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX3V1aWQiOjQzMTI2MzMxODcxMjE5NzEyLCJuYmYiOjE2NDkzMDQ1ODZ9.FvG8hY0R6D9lO1t4GR1bDhQVayGU5gHVCcy0SIX1r0c 授权信息
+ * @apiHeader {String = zh-CN,en-US} accept-language = zh-CN
+ * @apiQuery { Boolean } [ qualified ] 是否合格
+ * @apiQuery { String } [ keyword ] 执行用户名、任务名称、房间名称
+ * @apiQuery { Date } [ beginTimeStart ] 任务执行开始时间 开始时间
+ * @apiQuery { Date } [ beginTimeEnd ] 任务执行开始时间 结束时间
+ * @apiQuery { Integer } [ page = 1 ] 页码
+ * @apiQuery { Integer } [ size = 10 ] 页大小
+ * @apiQuery { String { ^[-+][\w]+ } } [ order = -id ] 排序规则(默认ID倒序),排序字段前加:+表示正序 -表示倒序
+ * @apiSuccess { Object } data 数据
+ * @apiSuccess { Long } data.total 数据总数
+ * @apiSuccess { Object[] } data.list 数据列表
+ * @apiSuccess { Long } data.list.id 任务id
+ * @apiSuccess { String } data.list.name 任务名称
+ * @apiSuccess { Long } data.list.roomId 房间id
+ * @apiSuccess { String } data.list.roomName 房间名称
+ * @apiSuccess { Date } data.list.time 巡检时间
+ * @apiSuccess { String } data.list.username 巡检人员
+ * @apiSuccess { String } message 信息
+ * @apiSuccess { Integer } code 状态码
+ * @apiSuccessExample Response
+ *
+ * {"data":{"total":1, "list":[{"id":1, "name":"", "roomId":1, "roomName":"", "time":1653458692072, "username":""}]}, "message":"", "code":1}
+ */
+
+/**
+ * @api {post} /v1/visitor/audit/add 01.进入登记
+ * @apiName 进入登记
+ * @apiGroup 访客审批
+ * @apiVersion 1.0.2
+ * @apiHeader {String = application/json} Content-Type = application/json
+ * @apiHeader {String = zh-CN,en-US} accept-language = zh-CN
+ * @apiBody { String } openid 用户openid
+ * @apiBody { String } username 访客姓名
+ * @apiBody { String { ^1[345789][0-9]\d{8}$ } } userPhone 访客手机号
+ * @apiBody { String } company 访客公司
+ * @apiBody { Integer } duration 访问时长(小时)
+ * @apiBody { String } [ itineraryCode ] 行程码
+ * @apiBody { String } [ healthCode ] 健康码
+ * @apiBody { Boolean } [ highRisk ] 是否高风险
+ * @apiBody { String } reason 事由
+ * @apiBody { String } [ information ] 审核资料
+ * @apiSuccess { String } data 数据
+ * @apiSuccess { String } message 信息
+ * @apiSuccess { Integer } code 状态码
+ * @apiSuccessExample Response
+ *
+ * {"data":"", "message":"", "code":1}
+ */
+
+/**
+ * @api {put} /v1/visitor/audit/update 03.出场核销
+ * @apiName 出场核销
+ * @apiGroup 访客审批
+ * @apiVersion 1.0.2
+ * @apiHeader {String = application/json} Content-Type = application/json
+ * @apiHeader {String = zh-CN,en-US} accept-language = zh-CN
+ * @apiBody { Long } id 入场记录id
+ * @apiBody { String } [ remark ] 出场备注
+ * @apiSuccess { String } data 数据
+ * @apiSuccess { String } message 信息
+ * @apiSuccess { Integer } code 状态码
+ * @apiSuccessExample Response
+ *
+ * {"data":"", "message":"", "code":1}
+ */

+ 61 - 0
applications/patrol/patrol-app/api/patrol-app_1.0.3.api

@@ -0,0 +1,61 @@
+
+/**
+ * @api {get} /v1/patrol/task/list 01.巡检计划
+ * @apiName 巡检计划
+ * @apiGroup 巡检任务
+ * @apiVersion 1.0.3
+ * @apiHeader {String = application/x-www-form-urlencoded} Content-Type = application/x-www-form-urlencoded
+ * @apiHeader {String} Authorization = eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX3V1aWQiOjQzMTI2MzMxODcxMjE5NzEyLCJuYmYiOjE2NDkzMDQ1ODZ9.FvG8hY0R6D9lO1t4GR1bDhQVayGU5gHVCcy0SIX1r0c 授权信息
+ * @apiHeader {String = zh-CN,en-US} accept-language = zh-CN
+ * @apiQuery { Date } [ beginTimeStart ] 任务执行开始时间 开始时间
+ * @apiQuery { Date } [ beginTimeEnd ] 任务执行开始时间 结束时间
+ * @apiQuery { Integer } [ page = 1 ] 页码
+ * @apiQuery { Integer } [ size = 10 ] 页大小
+ * @apiSuccess { Object } data 数据
+ * @apiSuccess { Long } data.total 数据总数
+ * @apiSuccess { Object[] } data.list 数据列表
+ * @apiSuccess { Long } data.list.id id 主键
+ * @apiSuccess { String } data.list.name 名称
+ * @apiSuccess { Date } data.list.beginTime 任务执行开始时间
+ * @apiSuccess { Date } data.list.endTime 任务执行结束时间
+ * @apiSuccess { Integer } data.list.status 状态 1未开始、2进行中、3正常完成、4超时漏检、5超时完成
+ * @apiSuccess { Integer } data.list.total 计划巡检房间数
+ * @apiSuccess { Integer } data.list.completed 已经完成房间数
+ * @apiSuccess { Float } data.list.completionRate 完成率
+ * @apiSuccess { String } message 信息
+ * @apiSuccess { Integer } code 状态码
+ * @apiSuccessExample Response
+ *
+ * {"data":{"total":1, "list":[{"id":1, "name":"", "beginTime":1728959661005, "endTime":1728959661005, "status":1, "total":1, "completed":1, "completionRate":1.0}]}, "message":"", "code":1}
+ */
+
+/**
+ * @api {get} /v1/patrol/task/list/record 09.巡检记录
+ * @apiName 巡检记录
+ * @apiGroup 巡检任务
+ * @apiVersion 1.0.3
+ * @apiHeader {String = application/x-www-form-urlencoded} Content-Type = application/x-www-form-urlencoded
+ * @apiHeader {String} Authorization = eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX3V1aWQiOjQzMTI2MzMxODcxMjE5NzEyLCJuYmYiOjE2NDkzMDQ1ODZ9.FvG8hY0R6D9lO1t4GR1bDhQVayGU5gHVCcy0SIX1r0c 授权信息
+ * @apiHeader {String = zh-CN,en-US} accept-language = zh-CN
+ * @apiQuery { Boolean } [ qualified ] 是否合格
+ * @apiQuery { String } [ keyword ] 执行用户名、任务名称、房间名称
+ * @apiQuery { Date } [ beginTimeStart ] 任务完成开始时间 开始时间
+ * @apiQuery { Date } [ beginTimeEnd ] 任务完成开始时间 结束时间
+ * @apiQuery { Integer } [ page = 1 ] 页码
+ * @apiQuery { Integer } [ size = 10 ] 页大小
+ * @apiQuery { String { ^[-+][\w]+ } } [ order = -id ] 排序规则(默认ID倒序),排序字段前加:+表示正序 -表示倒序
+ * @apiSuccess { Object } data 数据
+ * @apiSuccess { Long } data.total 数据总数
+ * @apiSuccess { Object[] } data.list 数据列表
+ * @apiSuccess { Long } data.list.id 任务id
+ * @apiSuccess { String } data.list.name 任务名称
+ * @apiSuccess { Long } data.list.roomId 房间id
+ * @apiSuccess { String } data.list.roomName 房间名称
+ * @apiSuccess { Date } data.list.time 巡检时间
+ * @apiSuccess { String } data.list.username 巡检人员
+ * @apiSuccess { String } message 信息
+ * @apiSuccess { Integer } code 状态码
+ * @apiSuccessExample Response
+ *
+ * {"data":{"total":1, "list":[{"id":1, "name":"", "roomId":1, "roomName":"", "time":1728959661006, "username":""}]}, "message":"", "code":1}
+ */

+ 20 - 0
applications/patrol/patrol-app/apidoc.json

@@ -0,0 +1,20 @@
+{
+  "name" : "patrol-app",
+  "version" : "1.0.3",
+  "description" : "巡检系统-微信小程序",
+  "title" : "巡检系统",
+  "url" : "https://smartjingan.xyz/patrol-app",
+  "sampleUrl" : "https://smartjingan.xyz/patrol-app",
+  "urlR" : "http://localhost:8898",
+  "sampleUrlR" : "http://localhost:8898",
+  "order" : [ "用户", "楼栋", "楼层", "房间", "设备", "检查项", "检查路线", "物品类别", "物品", "临时任务", "临时任务反馈", "巡检任务", "巡检任务记录", "微信小程序", "制度管理", "访客审批", "用户评价", "文件" ],
+  "template" : {
+    "forceLanguage" : "zh",
+    "showRequiredLabels" : true,
+    "withCompare" : false
+  },
+  "header" : {
+    "title" : "文档说明",
+    "filename" : "apidoc_header.md"
+  }
+}

+ 5 - 0
applications/patrol/patrol-app/apidoc_header.md

@@ -0,0 +1,5 @@
+## 请求状态码
+
+    200:成功
+    499:客户端逻辑错误
+    500:服务器逻辑错误

+ 109 - 0
applications/patrol/patrol-app/pom.xml

@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>patrol</artifactId>
+        <groupId>com.flyhigh</groupId>
+        <version>1.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.chuanghai.patrol</groupId>
+    <artifactId>patrol-app</artifactId>
+    <name>patrol-app</name>
+    <version>1.0.3</version>
+    <packaging>jar</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.flyhigh</groupId>
+            <artifactId>core</artifactId>
+            <version>1.0.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.jdom</groupId>
+            <artifactId>jdom2</artifactId>
+        </dependency>
+
+        <!-- lombok插件-->
+        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <scope>compile</scope>
+        </dependency>
+
+        <!-- 验证码 -->
+        <dependency>
+            <groupId>com.github.penggle</groupId>
+            <artifactId>kaptcha</artifactId>
+            <exclusions>
+                <exclusion>
+                    <artifactId>javax.servlet-api</artifactId>
+                    <groupId>javax.servlet</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <!-- 测试环境-->
+        <!-- https://mvnrepository.com/artifact/junit/junit -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <finalName>${project.artifactId}</finalName>
+        <plugins>
+            <!-- 工程清理插件 -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-clean-plugin</artifactId>
+            </plugin>
+
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+            </plugin>
+
+            <!-- 单元测试插件 -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+            </plugin>
+
+            <!-- Mybatis、VUE代码生成插件 -->
+            <plugin>
+                <groupId>com.flyhigh</groupId>
+                <artifactId>mybatis-generate-maven-plugin</artifactId>
+            </plugin>
+
+            <!-- API文档、接口权限处理插件 -->
+            <plugin>
+                <groupId>com.flyhigh</groupId>
+                <artifactId>apidoc-maven-plugin</artifactId>
+                <configuration>
+                    <strings combine.children="append">
+                        <Authorization>eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX3V1aWQiOjQzMTI2MzMxODcxMjE5NzEyLCJuYmYiOjE2NDkzMDQ1ODZ9.FvG8hY0R6D9lO1t4GR1bDhQVayGU5gHVCcy0SIX1r0c</Authorization>
+                    </strings>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 19 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/PatrolAppApplication.java

@@ -0,0 +1,19 @@
+package com.chuanghai.patrol;
+
+import com.flyhigh.core.Application;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.scheduling.annotation.EnableAsync;
+
+@Slf4j
+@EnableAsync
+@SpringBootApplication(scanBasePackages = {"com.flyhigh", "com.chuanghai"})
+@RequiredArgsConstructor
+public class PatrolAppApplication extends Application {
+
+    public static void main(String[] args) {
+        SpringApplication.run(PatrolAppApplication.class, args);
+    }
+}

+ 91 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/aspect/SysLogAspect.java

@@ -0,0 +1,91 @@
+package com.chuanghai.patrol.aspect;
+
+import com.chuanghai.patrol.config.AppConstant;
+import com.chuanghai.patrol.dao.SystemLogMapper;
+import com.chuanghai.patrol.entity.Result;
+import com.chuanghai.patrol.model.SystemLog;
+import com.flyhigh.core.exception.CustomizeException;
+import com.flyhigh.core.util.DateUtil;
+import org.apache.http.HttpStatus;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
+import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
+import org.springframework.stereotype.Component;
+
+import java.lang.reflect.Method;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * 操作日志记录
+ */
+@Aspect
+@Component
+public class SysLogAspect extends com.flyhigh.core.aspect.SysLogAspect {
+    /**
+     * 日志服务
+     */
+    private final SystemLogMapper systemLogMapper;
+
+    public SysLogAspect(SystemLogMapper systemLogMapper, Jackson2ObjectMapperBuilder builder) {
+        super(builder, SysLogAspect.class.getPackage().getName().substring(0, SysLogAspect.class.getPackage().getName().lastIndexOf(".")));
+        this.systemLogMapper = systemLogMapper;
+    }
+
+    @Override
+    protected void success(ProceedingJoinPoint joinPoint, Object result, Long time) {
+        SystemLog log = createLog(joinPoint);
+        log.setTime(time);
+        log.setResponse(toJSONString(result));
+        log.setSuccess(true);
+        systemLogMapper.insertSelective(log);
+    }
+
+    @Override
+    protected void fail(JoinPoint joinPoint, Throwable exception, Long time, String fileName, Integer lineNumber) {
+        SystemLog log = createLog(joinPoint);
+        if (exception instanceof CustomizeException) {
+            String message = tr(exception.getMessage());
+            Result<Object> result = new Result<>(null, message, ((CustomizeException) exception).getCode());
+            log.setResponse(toJSONString(result));
+        } else {
+            log.setResponse(toJSONString(new Result<>(null, tr("sys_server_err") + ":" + exception.getMessage(), HttpStatus.SC_INTERNAL_SERVER_ERROR)));
+        }
+        log.setSuccess(Boolean.FALSE);
+        log.setTime(time);
+        log.setFileName(fileName);
+        log.setLineNumber(lineNumber);
+        systemLogMapper.insertSelective(log);
+    }
+
+    private SystemLog createLog(JoinPoint joinPoint) {
+        SystemLog log = new SystemLog();
+        log.setPlatform(2);
+        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
+        Method method = signature.getMethod();
+        // 请求的方法参数值
+        Object[] args = joinPoint.getArgs();
+        // 请求的方法参数名称
+        String[] paramNames = new LocalVariableTableParameterNameDiscoverer().getParameterNames(method);
+        if (Objects.nonNull(args) && Objects.nonNull(paramNames)) {
+            Map<String, Object> params = new LinkedHashMap<>(paramNames.length);
+            for (int i = 0; i < args.length; i++) {
+                Object arg = args[i];
+                params.put(paramNames[i], ignore(arg) ? null : arg);
+            }
+            log.setRequest(toJSONString(params));
+        }
+        log.setCreateTime(DateUtil.now());
+        getRequest().ifPresent(r -> {
+            log.setMethod(r.getMethod());
+            log.setUri(r.getRequestURI());
+            log.setUserId((Long) r.getAttribute(AppConstant.USER_ID));
+            log.setUserIp(getIp());
+        });
+        return log;
+    }
+}

+ 148 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/config/AppConstant.java

@@ -0,0 +1,148 @@
+package com.chuanghai.patrol.config;
+
+import com.flyhigh.core.config.CoreConstant;
+
+/**
+ * 自定义常量
+ */
+public class AppConstant extends CoreConstant {
+    /**
+     * 用户名
+     */
+    public static final String USERNAME = "username";
+
+    /**
+     * 超级管理员数据ID
+     */
+    public static final long SUPPER_ADMIN_ID = 1L;
+
+    /**
+     * 级联数据顶层数据父ID
+     */
+    public static final long PARENT_ID = 0L;
+
+    /**
+     * 机柜设备
+     */
+    public static final int DEVICE_TYPE_CABINET = 1;
+
+    /**
+     * 正在处理
+     */
+    public static final int TEMPORARY_TASK_STATUS_PROCESSING = 1;
+
+    /**
+     * 已经完成
+     */
+    public static final int TEMPORARY_TASK_STATUS_COMPLETED = 2;
+
+    /**
+     * 已经取消
+     */
+    public static final int TEMPORARY_TASK_STATUS_CANCELLED = 3;
+
+    /**
+     * 超时任务
+     */
+    public static final int TEMPORARY_TASK_STATUS_TIMEOUT = 4;
+
+    /**
+     * 未提交
+     */
+    public static final int TEMPORARY_TASK_AUDIT_STATUS_UN_SUBMITTED = 1;
+
+    /**
+     * 待审核
+     */
+    public static final int TEMPORARY_TASK_AUDIT_STATUS_PENDING_REVIEW = 2;
+
+    /**
+     * 不通过
+     */
+    public static final int TEMPORARY_TASK_AUDIT_STATUS_FAIL = 3;
+
+    /**
+     * 选择项
+     */
+    public static final int CHECK_ITEM_TYPE_SELECT = 1;
+
+    /**
+     * 数字项
+     */
+    public static final int CHECK_ITEM_TYPE_NUM = 2;
+
+    /**
+     * 文本项
+     */
+    public static final int CHECK_ITEM_TYPE_TXT = 3;
+
+    /**
+     * 拍照项
+     */
+    public static final int CHECK_ITEM_TYPE_PHOTO = 4;
+
+    /**
+     * 未开始
+     */
+    public static final int TASK_STATE_NOT_STARTED = 1;
+
+    /**
+     * 进行中
+     */
+    public static final int TASK_STATE_PROCESSING = 2;
+
+    /**
+     * 正常完成
+     */
+    public static final int TASK_STATE_COMPLETED = 3;
+
+    /**
+     * 超时漏检
+     */
+    public static final int TASK_STATE_OMISSION = 4;
+
+    /**
+     * 超时完成
+     */
+    public static final int TASK_STATE_TIMEOUT_COMPLETED = 5;
+
+    /**
+     * 执行模式 其中一人
+     */
+    public static final int RUN_MODEL_ONE = 1;
+
+    /**
+     * 执行模式 每人分别
+     */
+    public static final int RUN_MODEL_ALL = 2;
+
+    /**
+     * 考勤:任务
+     */
+    public static final int ATTENDANCE_TASK = 1;
+
+    /**
+     * 考勤:评分
+     */
+    public static final int ATTENDANCE_SCORE = 2;
+
+    /**
+     * 考勤:初始
+     */
+    public static final int ATTENDANCE_INITIAL = 3;
+
+    /**
+     * 未审核
+     */
+    public static final int NOT_AUDIT = 1;
+
+    /**
+     * 审核通过
+     */
+    public static final int AUDIT_PASS = 2;
+
+    /**
+     * 审核拒绝
+     */
+    public static final int AUDIT_REFUSE = 3;
+}

+ 37 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/config/AppProperties.java

@@ -0,0 +1,37 @@
+package com.chuanghai.patrol.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+import java.io.File;
+import java.util.regex.Matcher;
+
+/**
+ * 应用配置
+ */
+@Data
+@Configuration
+@ConfigurationProperties("app")
+public class AppProperties {
+    /**
+     * 文件上传保存路径
+     */
+    private String filePath;
+    /**
+     * 缓存文件位置
+     */
+    private String tempFilePath;
+    /**
+     * 服务器域名
+     */
+    private String hostname;
+
+    public void setFilePath(String filePath) {
+        this.filePath = filePath.replaceAll("[/\\\\]", Matcher.quoteReplacement(File.separator));
+    }
+
+    public void setTempFilePath(String tempFilePath) {
+        this.tempFilePath = tempFilePath.replaceAll("[/\\\\]", Matcher.quoteReplacement(File.separator));
+    }
+}

+ 47 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/config/CaptchaConfig.java

@@ -0,0 +1,47 @@
+package com.chuanghai.patrol.config;
+
+import com.google.code.kaptcha.impl.DefaultKaptcha;
+import com.google.code.kaptcha.util.Config;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.Properties;
+
+import static com.google.code.kaptcha.Constants.*;
+
+/**
+ * 验证码配置
+ */
+@Configuration
+public class CaptchaConfig {
+    @Bean
+    public DefaultKaptcha captcha() {
+        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
+        Properties properties = new Properties();
+        // 是否有边框 默认为true 我们可以自己设置yes,no
+        properties.setProperty(KAPTCHA_BORDER, "no");
+        // 验证码文本字符颜色 默认为Color.BLACK
+        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");
+        // 验证码图片宽度 默认为200
+        properties.setProperty(KAPTCHA_IMAGE_WIDTH, "100");
+        // 验证码图片高度 默认为50
+        properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "30");
+        // 验证码文本字符大小 默认为40
+        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "22");
+        // KAPTCHA_SESSION_KEY
+        properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode");
+        //文本集合,验证码值从此集合中获取 0qwertyuiopasdfghjklzxcvbnm
+        properties.setProperty("kaptcha.textproducer.char.string", "0123456789");
+        // 验证码文本字符长度 默认为5
+        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
+        // 验证码文本字符间距 默认为2
+        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3");
+        // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
+        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
+        // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
+        properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
+        Config config = new Config(properties);
+        defaultKaptcha.setConfig(config);
+        return defaultKaptcha;
+    }
+}

+ 40 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/controller/checkroute/CheckRouteExtController.java

@@ -0,0 +1,40 @@
+package com.chuanghai.patrol.controller.checkroute;
+
+import com.chuanghai.patrol.entity.Result;
+import com.chuanghai.patrol.service.checkroute.CheckRouteExtService;
+import com.chuanghai.patrol.vo.OptionVO;
+import com.flyhigh.core.annotation.IgnorePermissionsCheck;
+import com.flyhigh.core.annotation.RequireLogin;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+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 java.util.List;
+
+/**
+ * 检查路线
+ */
+@Validated
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/v1/check/route")
+public class CheckRouteExtController {
+    private final CheckRouteExtService checkRouteExtService;
+
+    /**
+     * 巡检路线
+     *
+     * @param name 路线名称
+     * @return 路线列表
+     * @since 1.0.0
+     */
+    @RequireLogin
+    @GetMapping("/list/option")
+    @IgnorePermissionsCheck
+    public Result<List<OptionVO>> listRoomOption(@RequestParam(required = false) String name) {
+        return Result.ok(checkRouteExtService.selectOptionList(name));
+    }
+}

+ 72 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/controller/common/FileController.java

@@ -0,0 +1,72 @@
+package com.chuanghai.patrol.controller.common;
+
+import com.chuanghai.patrol.config.AppProperties;
+import com.chuanghai.patrol.entity.Result;
+import com.flyhigh.core.ApplicationContext;
+import com.flyhigh.core.config.CoreConstant;
+import com.flyhigh.core.exception.SystemRuntimeException;
+import com.flyhigh.core.util.FileUtil;
+import com.flyhigh.core.util.HttpUtil;
+import lombok.RequiredArgsConstructor;
+import org.apache.commons.io.FileUtils;
+import org.apache.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.constraints.NotNull;
+import java.io.File;
+import java.util.List;
+
+/**
+ * 文件
+ */
+@Validated
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/v1/file")
+public class FileController extends ApplicationContext {
+    private final AppProperties appProperties;
+
+    /**
+     * 文件上传
+     *
+     * @param file 文件
+     * @return 文件存储路径
+     * @since 1.0.0
+     */
+    @PostMapping("/upload")
+    public Result<String> upload(@RequestParam @NotNull MultipartFile file) {
+        return Result.ok(FileUtil.saveMultipartFile(file, appProperties.getFilePath(), null, HttpUtil.getServerAddress(appProperties.getHostname())));
+    }
+
+    /**
+     * 多文件上传
+     *
+     * @return 文件存储路径
+     * @since 1.0.0
+     */
+    @PostMapping("/uploads")
+    public Result<List<String>> uploads(HttpServletRequest request) {
+        return Result.ok(FileUtil.saveMultipartFile(request, appProperties.getFilePath(), null, HttpUtil.getServerAddress(appProperties.getHostname())));
+    }
+
+    /**
+     * 文件下载
+     *
+     * @param path 文件存储路径
+     * @since 1.0.0
+     */
+    @GetMapping("/query/{path}")
+    public void download(@PathVariable("path") String path, HttpServletResponse response) {
+        try {
+            response.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.ALL_VALUE);
+            FileUtils.copyFile(new File(appProperties.getFilePath() + File.separator + path), response.getOutputStream());
+        } catch (Exception e) {
+            throw new SystemRuntimeException(CoreConstant.CLIENT_LOGIC_ERROR, e);
+        }
+    }
+}

+ 52 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/controller/device/DeviceBuildingExtController.java

@@ -0,0 +1,52 @@
+package com.chuanghai.patrol.controller.device;
+
+import com.chuanghai.patrol.entity.Result;
+import com.chuanghai.patrol.service.device.DeviceBuildingExtService;
+import com.chuanghai.patrol.vo.OptionVO;
+import com.flyhigh.core.annotation.IgnorePermissionsCheck;
+import com.flyhigh.core.annotation.RequireLogin;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * 楼栋
+ */
+@Validated
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/v1/device/building")
+public class DeviceBuildingExtController {
+    private final DeviceBuildingExtService deviceBuildingExtService;
+
+    /**
+     * 获取所有楼栋选项列表
+     *
+     * @return 楼层列表
+     * @since 1.0.0
+     */
+    @RequireLogin
+    @GetMapping("/list/option")
+    @IgnorePermissionsCheck
+    public Result<List<OptionVO>> listOption() {
+        return Result.ok(deviceBuildingExtService.selectOptionList());
+    }
+
+
+    /**
+     * 获取所有楼栋选项列表
+     *
+     * @return 楼层列表
+     * @since 1.0.0
+     */
+    @GetMapping("/testAppOpen")
+    @IgnorePermissionsCheck
+    public Result<String> testWebOpen() {
+        return Result.ok("发布成功");
+    }
+
+}

+ 43 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/controller/device/DeviceExtController.java

@@ -0,0 +1,43 @@
+package com.chuanghai.patrol.controller.device;
+
+import com.chuanghai.patrol.entity.PageInfo;
+import com.chuanghai.patrol.entity.Result;
+import com.chuanghai.patrol.service.device.DeviceExtService;
+import com.chuanghai.patrol.vo.DeviceVO;
+import com.flyhigh.core.annotation.IgnorePermissionsCheck;
+import com.flyhigh.core.annotation.RequireLogin;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+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;
+
+/**
+ * 设备
+ */
+@Validated
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/v1/device")
+public class DeviceExtController {
+    private final DeviceExtService deviceExtService;
+
+    /**
+     * 获取房间中的设备
+     *
+     * @param roomId 房间id
+     * @param page   页码
+     * @param size   页大小
+     * @return 设备列表
+     * @since 1.0.0
+     */
+    @RequireLogin
+    @GetMapping("/list")
+    @IgnorePermissionsCheck
+    public Result<PageInfo<DeviceVO>> list(@RequestParam Long roomId,
+                                           @RequestParam(defaultValue = "1") Integer page,
+                                           @RequestParam(defaultValue = "10") Integer size) {
+        return Result.ok(deviceExtService.selectList(roomId, page, size));
+    }
+}

+ 41 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/controller/device/DeviceFloorExtController.java

@@ -0,0 +1,41 @@
+package com.chuanghai.patrol.controller.device;
+
+import com.chuanghai.patrol.entity.Result;
+import com.chuanghai.patrol.service.device.DeviceFloorExtService;
+import com.chuanghai.patrol.vo.OptionVO;
+import com.flyhigh.core.annotation.IgnorePermissionsCheck;
+import com.flyhigh.core.annotation.RequireLogin;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * 楼层
+ */
+@Validated
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/v1/device/floor")
+public class DeviceFloorExtController {
+    private final DeviceFloorExtService deviceFloorExtService;
+
+    /**
+     * 获取楼栋中的所有楼层选项
+     *
+     * @param buildingId 楼栋id
+     * @return 楼层列表
+     * @since 1.0.0
+     */
+    @RequireLogin
+    @GetMapping("/list/option/{buildingId}")
+    @IgnorePermissionsCheck
+    public Result<List<OptionVO>> listOption(@PathVariable Long buildingId) {
+        return Result.ok(deviceFloorExtService.selectOptionList(buildingId));
+    }
+
+}

+ 75 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/controller/device/DeviceRoomExtController.java

@@ -0,0 +1,75 @@
+package com.chuanghai.patrol.controller.device;
+
+import com.chuanghai.patrol.entity.PageInfo;
+import com.chuanghai.patrol.entity.Result;
+import com.chuanghai.patrol.service.device.DeviceRoomExtService;
+import com.chuanghai.patrol.vo.DeviceRoomDetailsVO;
+import com.chuanghai.patrol.vo.DeviceRoomOptionVO;
+import com.chuanghai.patrol.vo.OptionVO;
+import com.flyhigh.core.annotation.IgnorePermissionsCheck;
+import com.flyhigh.core.annotation.RequireLogin;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 房间
+ */
+@Validated
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/v1/device/room")
+public class DeviceRoomExtController {
+    private final DeviceRoomExtService deviceRoomExtService;
+
+    /**
+     * 获取巡检路线中的房间
+     *
+     * @param name 房间名称
+     * @param page 页码
+     * @param size 页大小
+     * @param id   检查路线id
+     * @return 检查路线
+     * @since 1.0.0
+     */
+    @RequireLogin
+    @GetMapping("/list")
+    @IgnorePermissionsCheck
+    public Result<PageInfo<DeviceRoomOptionVO>> list(@RequestParam(required = false) String name,
+                                                     @RequestParam(required = false) Long id,
+                                                     @RequestParam(defaultValue = "1") Integer page,
+                                                     @RequestParam(defaultValue = "10") Integer size) {
+        return Result.ok(deviceRoomExtService.selectList(name, id, page, size));
+    }
+
+    /**
+     * 查询房间详情
+     *
+     * @param id      房间id
+     * @param routeId 路线id
+     * @return 房间
+     * @since 1.0.0
+     */
+    @RequireLogin
+    @GetMapping("/query")
+    @IgnorePermissionsCheck
+    public Result<DeviceRoomDetailsVO> query(@RequestParam Long id, @RequestParam Long routeId) {
+        return Result.ok(deviceRoomExtService.query(id, routeId));
+    }
+
+    /**
+     * 获取楼层中的所有房间选项
+     *
+     * @param floorId 楼层id
+     * @return 房间列表
+     * @since 1.0.0
+     */
+    @RequireLogin
+    @GetMapping("/list/option/{floorId}")
+    @IgnorePermissionsCheck
+    public Result<List<OptionVO>> listRoomOption(@PathVariable Long floorId) {
+        return Result.ok(deviceRoomExtService.selectOptionList(floorId));
+    }
+}

+ 174 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/controller/patrol/PatrolTaskExtController.java

@@ -0,0 +1,174 @@
+package com.chuanghai.patrol.controller.patrol;
+
+import com.chuanghai.patrol.entity.PageInfo;
+import com.chuanghai.patrol.entity.Result;
+import com.chuanghai.patrol.from.PatrolTaskRecordUpdateFrom;
+import com.chuanghai.patrol.service.patrol.PatrolTaskExtService;
+import com.chuanghai.patrol.vo.*;
+import com.flyhigh.core.annotation.IgnorePermissionsCheck;
+import com.flyhigh.core.annotation.RequireLogin;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.constraints.Pattern;
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * 巡检任务
+ */
+@Validated
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/v1/patrol/task")
+public class PatrolTaskExtController {
+    private final PatrolTaskExtService patrolTaskExtService;
+
+    /**
+     * 巡检计划
+     *
+     * @param beginTimeStart 任务执行开始时间 开始时间
+     * @param beginTimeEnd   任务执行开始时间 结束时间
+     * @param page           页码
+     * @param size           页大小
+     * @return 巡检任务列表
+     * @since 1.0.3
+     */
+    @RequireLogin
+    @GetMapping("/list")
+    @IgnorePermissionsCheck
+    public Result<PageInfo<PatrolTaskVO>> list(@RequestParam(required = false) LocalDateTime beginTimeStart, @RequestParam(required = false) LocalDateTime beginTimeEnd, @RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer size) {
+        return Result.ok(patrolTaskExtService.selectList(beginTimeStart, beginTimeEnd, page, size));
+    }
+
+    /**
+     * 选择计划
+     *
+     * @param roomId 房间id
+     * @return 巡检任务列表
+     * @since 1.0.1
+     */
+    @RequireLogin
+    @GetMapping("/list/room")
+    @IgnorePermissionsCheck
+    public Result<List<PatrolTaskVO>> listByRoom(@RequestParam Long roomId) {
+        return Result.ok(patrolTaskExtService.selectListByRoom(roomId));
+    }
+
+    /**
+     * 巡检进度
+     *
+     * @param id 巡检任务id
+     * @return 巡检进度
+     * @since 1.0.1
+     */
+    @RequireLogin
+    @GetMapping("/query/rate/{id}")
+    @IgnorePermissionsCheck
+    public Result<PatrolRateVO> queryRate(@PathVariable Long id) {
+        return Result.ok(patrolTaskExtService.queryRate(id));
+    }
+
+    /**
+     * 巡检详情
+     *
+     * @param taskId 巡检任务id
+     * @param roomId 房间id
+     * @return 巡检详情
+     * @since 1.0.0
+     */
+    @RequireLogin
+    @GetMapping("/query/record")
+    @IgnorePermissionsCheck
+    public Result<PatrolDetailsVO> queryRecord(@RequestParam Long taskId, @RequestParam Long roomId) {
+        return Result.ok(patrolTaskExtService.queryRecord(taskId, roomId));
+    }
+
+    /**
+     * 巡检_巡检
+     *
+     * @param taskId 巡检任务id
+     * @param roomId 房间id
+     * @return 巡检房间详情
+     * @since 1.0.0
+     */
+    @RequireLogin
+    @GetMapping("/query")
+    @IgnorePermissionsCheck
+    public Result<PatrolRoomDetailsVO> query(@RequestParam Long taskId, @RequestParam Long roomId) {
+        return Result.ok(patrolTaskExtService.query(taskId, roomId));
+    }
+
+    /**
+     * 未开始任务房间详情
+     *
+     * @param taskId 巡检任务id
+     * @param roomId 房间id
+     * @return 房间
+     * @since 1.0.0
+     */
+    @RequireLogin
+    @GetMapping("/room")
+    @IgnorePermissionsCheck
+    public Result<DeviceRoomDetailsVO> queryRoomDetails(@RequestParam Long taskId, @RequestParam Long roomId) {
+        return Result.ok(patrolTaskExtService.queryRoomDetails(taskId, roomId));
+    }
+
+    /**
+     * 巡检_完成
+     *
+     * @param patrolTaskRecordUpdateFrom 巡检任务记录
+     * @return 是否成功
+     * @since 1.0.0
+     */
+    @RequireLogin
+    @PutMapping("/update")
+    @IgnorePermissionsCheck
+    public Result<Boolean> update(@RequestBody @Validated PatrolTaskRecordUpdateFrom patrolTaskRecordUpdateFrom) {
+        return Result.ok(patrolTaskExtService.update(patrolTaskRecordUpdateFrom));
+    }
+
+    /**
+     * 巡检_记录
+     *
+     * @param taskId 巡检任务id
+     * @param roomId 房间id
+     * @param page   页码
+     * @param size   页大小
+     * @return 巡检记录
+     * @since 1.0.0
+     */
+    @RequireLogin
+    @GetMapping("/list/record/room")
+    @IgnorePermissionsCheck
+    public Result<PageInfo<PatrolRoomRecordVO>> listRoomRecord(@RequestParam Long taskId, @RequestParam Long roomId, @RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer size) {
+        return Result.ok(patrolTaskExtService.selectRoomRecordList(taskId, roomId, page, size));
+    }
+
+    /**
+     * 巡检记录
+     *
+     * @param qualified      是否合格
+     * @param keyword        执行用户名、任务名称、房间名称
+     * @param beginTimeStart 任务完成开始时间 开始时间
+     * @param beginTimeEnd   任务完成开始时间 结束时间
+     * @param page           页码
+     * @param size           页大小
+     * @param order          排序规则(默认ID倒序),排序字段前加:+表示正序 -表示倒序
+     * @return 巡检记录
+     * @since 1.0.3
+     */
+    @RequireLogin
+    @GetMapping("/list/record")
+    @IgnorePermissionsCheck
+    public Result<PageInfo<PatrolRecordVO>> listRecord(@RequestParam(required = false) Boolean qualified,
+                                                       @RequestParam(required = false) String keyword,
+                                                       @RequestParam(required = false) LocalDateTime beginTimeStart,
+                                                       @RequestParam(required = false) LocalDateTime beginTimeEnd,
+                                                       @RequestParam(defaultValue = "1") Integer page,
+                                                       @RequestParam(defaultValue = "10") Integer size,
+                                                       @RequestParam(defaultValue = "-id") @Validated @Pattern(regexp = "^[-+][\\w]+") String order) {
+        return Result.ok(patrolTaskExtService.selectRecordList(qualified, keyword, beginTimeStart, beginTimeEnd, page, size, order));
+    }
+}

+ 39 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/controller/system/SystemUserCommentExtController.java

@@ -0,0 +1,39 @@
+package com.chuanghai.patrol.controller.system;
+
+import com.chuanghai.patrol.entity.Result;
+import com.chuanghai.patrol.from.SystemUserCommentAddFrom;
+import com.chuanghai.patrol.model.SystemUserComment;
+import com.chuanghai.patrol.service.system.SystemUserCommentExtService;
+import com.flyhigh.core.annotation.IgnorePermissionsCheck;
+import com.flyhigh.core.annotation.RequireLogin;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+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;
+
+/**
+ * 用户评价
+ */
+@Validated
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/v1/system/user/comment")
+public class SystemUserCommentExtController {
+    private final SystemUserCommentExtService systemUserCommentExtService;
+
+    /**
+     * 添加用户评价
+     *
+     * @param systemUserCommentAddFrom 用户评价
+     * @return 用户评价
+     * @since 1.0.0
+     */
+    @RequireLogin
+    @PostMapping("/add")
+    @IgnorePermissionsCheck
+    public Result<SystemUserComment> add(@RequestBody SystemUserCommentAddFrom systemUserCommentAddFrom) {
+        return Result.ok(systemUserCommentExtService.add(systemUserCommentAddFrom));
+    }
+}

+ 108 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/controller/system/SystemUserExtController.java

@@ -0,0 +1,108 @@
+package com.chuanghai.patrol.controller.system;
+
+import com.chuanghai.patrol.entity.PageInfo;
+import com.chuanghai.patrol.entity.Result;
+import com.chuanghai.patrol.from.SystemUserLoginFrom;
+import com.chuanghai.patrol.from.SystemUserPasswordUpdateFrom;
+import com.chuanghai.patrol.service.system.SystemUserExtService;
+import com.chuanghai.patrol.vo.OptionVO;
+import com.chuanghai.patrol.vo.SystemCodeVO;
+import com.chuanghai.patrol.vo.SystemDeptUserVO;
+import com.chuanghai.patrol.vo.SystemLoginVO;
+import com.flyhigh.core.annotation.IgnorePermissionsCheck;
+import com.flyhigh.core.annotation.RequireLogin;
+import com.flyhigh.core.util.Base64;
+import com.google.code.kaptcha.impl.DefaultKaptcha;
+import lombok.RequiredArgsConstructor;
+import org.springframework.util.FastByteArrayOutputStream;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * 用户
+ */
+@Validated
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/v1/system/user")
+public class SystemUserExtController {
+    private final SystemUserExtService systemUserExtService;
+    private final DefaultKaptcha defaultKaptcha;
+
+    /**
+     * 生成验证码
+     */
+    @GetMapping("/code")
+    @IgnorePermissionsCheck
+    public Result<SystemCodeVO> getCode() throws IOException {
+        String code = defaultKaptcha.createText();
+        BufferedImage image = defaultKaptcha.createImage(code);
+        // 转换流信息写出
+        FastByteArrayOutputStream os = new FastByteArrayOutputStream();
+        ImageIO.write(image, "jpg", os);
+        return Result.ok(SystemCodeVO.builder().code(code).image("data:image/png;base64," + Base64.encode(os.toByteArray())).build());
+    }
+
+    /**
+     * 登录
+     *
+     * @param systemUserLoginFrom 用户信息
+     * @return 用户登录信息
+     * @since 1.0.1
+     */
+    @PostMapping("/login")
+    public Result<SystemLoginVO> login(@RequestBody @Validated SystemUserLoginFrom systemUserLoginFrom) {
+        return Result.ok(systemUserExtService.updateUserAuth(systemUserLoginFrom));
+    }
+
+    /**
+     * 更新用户密码
+     *
+     * @param systemUserPasswordUpdateFrom 用户密码信息
+     * @return 更新结果
+     * @since 1.0.0
+     */
+    @RequireLogin
+    @PutMapping("/update/password")
+    @IgnorePermissionsCheck
+    public Result<Boolean> updatePassword(@RequestBody @Validated SystemUserPasswordUpdateFrom systemUserPasswordUpdateFrom) {
+        return Result.ok(systemUserExtService.updatePassword(systemUserPasswordUpdateFrom));
+    }
+
+    /**
+     * 通过用户名或手机号查询用户选项
+     *
+     * @param keyword 用户名或手机号
+     * @param page    页码
+     * @param size    页大小
+     * @return 用户列表
+     * @since 1.0.0
+     */
+    @RequireLogin
+    @GetMapping("/list/option")
+    @IgnorePermissionsCheck
+    public Result<PageInfo<OptionVO>> listUserOption(@RequestParam(required = false) String keyword,
+                                                     @RequestParam(defaultValue = "1") Integer page,
+                                                     @RequestParam(defaultValue = "10") Integer size) {
+        return Result.ok(systemUserExtService.selectOptionList(keyword, page, size));
+    }
+
+    /**
+     * 查询部门用户
+     *
+     * @param username 用户名
+     * @return 用户列表
+     * @since 1.0.0
+     */
+    @RequireLogin
+    @GetMapping("/list/dept/user")
+    @IgnorePermissionsCheck
+    public Result<List<SystemDeptUserVO>> listUserOption(@RequestParam(required = false) String username) {
+        return Result.ok(systemUserExtService.selectDeptUserList(username));
+    }
+}

+ 170 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/controller/temporarytask/TemporaryTaskExtController.java

@@ -0,0 +1,170 @@
+package com.chuanghai.patrol.controller.temporarytask;
+
+import com.chuanghai.patrol.entity.PageInfo;
+import com.chuanghai.patrol.entity.Result;
+import com.chuanghai.patrol.from.TemporaryTaskAddFrom;
+import com.chuanghai.patrol.from.TemporaryTaskStatusUpdateFrom;
+import com.chuanghai.patrol.model.TemporaryTask;
+import com.chuanghai.patrol.service.temporarytask.TemporaryTaskExtService;
+import com.chuanghai.patrol.vo.TemporaryTaskStatusVO;
+import com.chuanghai.patrol.vo.TemporaryTaskVO;
+import com.flyhigh.core.annotation.IgnorePermissionsCheck;
+import com.flyhigh.core.annotation.RequireLogin;
+import lombok.RequiredArgsConstructor;
+import org.hibernate.validator.constraints.Range;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.constraints.Pattern;
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * 临时任务
+ */
+@Validated
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/v1/temporary/task")
+public class TemporaryTaskExtController {
+    private final TemporaryTaskExtService temporaryTaskExtService;
+
+    /**
+     * 添加临时任务
+     *
+     * @param temporaryTaskAddFrom 临时任务
+     * @return 临时任务
+     * @since 1.0.2
+     */
+    @RequireLogin
+    @PostMapping("/add")
+    @IgnorePermissionsCheck
+    public Result<TemporaryTask> add(@RequestBody @Validated TemporaryTaskAddFrom temporaryTaskAddFrom) {
+        return Result.ok(temporaryTaskExtService.add(temporaryTaskAddFrom));
+    }
+
+    /**
+     * 更新临时任务
+     *
+     * @param temporaryTaskStatusUpdateFrom 临时任务
+     * @return 临时任务
+     * @since 1.0.2
+     */
+    @RequireLogin
+    @PutMapping("/update")
+    @IgnorePermissionsCheck
+    public Result<TemporaryTask> update(@RequestBody @Validated TemporaryTaskStatusUpdateFrom temporaryTaskStatusUpdateFrom) {
+        return Result.ok(temporaryTaskExtService.update(temporaryTaskStatusUpdateFrom));
+    }
+
+    /**
+     * 分页查询临时任务
+     *
+     * @param title       任务标题
+     * @param type        任务类型 1:一般任务 2: 较急任务 3:紧急任务
+     * @param status      任务状态 1:正在处理 2:已经完成 3:已经取消 4:超时任务
+     * @param auditStatus 审核状态 1:未提交 2:待审核 3:不通过
+     * @param content     任务内容
+     * @param username    发起人名称
+     * @param executor    执行人名称
+     * @param startTime   开始日期
+     * @param endTime     结束日期
+     * @param page        页码
+     * @param size        页大小
+     * @param order       排序规则(默认ID倒序),排序字段前加:+表示正序 -表示倒序
+     * @return 临时任务列表
+     * @since 1.0.2
+     */
+    @RequireLogin
+    @GetMapping("/list")
+    @IgnorePermissionsCheck
+    public Result<PageInfo<TemporaryTaskVO>> list(@RequestParam(required = false) String title,
+                                                  @RequestParam(required = false) @Range(min = 1, max = 3) Integer type,
+                                                  @RequestParam(required = false) @Range(min = 1, max = 4) Integer status,
+                                                  @RequestParam(required = false) @Range(min = 1, max = 3) Integer auditStatus,
+                                                  @RequestParam(required = false) String content,
+                                                  @RequestParam(required = false) String username,
+                                                  @RequestParam(required = false) String executor,
+                                                  @RequestParam(required = false) LocalDateTime startTime,
+                                                  @RequestParam(required = false) LocalDateTime endTime,
+                                                  @RequestParam(defaultValue = "1") Integer page,
+                                                  @RequestParam(defaultValue = "10") Integer size,
+                                                  @RequestParam(defaultValue = "-id") @Validated @Pattern(regexp = "^[-+][\\w]+") String order) {
+        return Result.ok(temporaryTaskExtService.selectList(title, type, status, auditStatus, content, username, executor, startTime, endTime, page, size, order));
+    }
+
+    /**
+     * 我收到的临时任务统计
+     *
+     * @return 统计数据
+     * @since 1.0.0
+     */
+    @RequireLogin
+    @GetMapping("/list/receive/statistical")
+    @IgnorePermissionsCheck
+    public Result<List<TemporaryTaskStatusVO>> listReceiveStatistical() {
+        return Result.ok(temporaryTaskExtService.selectReceiveStatisticalList());
+    }
+
+    /**
+     * 我发出的临时任务统计
+     *
+     * @return 统计数据
+     * @since 1.0.0
+     */
+    @RequireLogin
+    @GetMapping("/list/publish/statistical")
+    @IgnorePermissionsCheck
+    public Result<List<TemporaryTaskStatusVO>> listPublishStatistical() {
+        return Result.ok(temporaryTaskExtService.selectPublishStatisticalList());
+    }
+
+    /**
+     * 我收到的临时任务列表
+     *
+     * @param status 任务状态 1:正在处理 2:已经完成 3:已经取消 4:超时任务
+     * @return 临时任务列表
+     * @since 1.0.2
+     */
+    @RequireLogin
+    @GetMapping("/list/receive")
+    @IgnorePermissionsCheck
+    public Result<PageInfo<TemporaryTaskVO>> listReceive(@RequestParam @Range(min = 1, max = 4) Integer status,
+                                                         @RequestParam(defaultValue = "1") Integer page,
+                                                         @RequestParam(defaultValue = "10") Integer size,
+                                                         @RequestParam(defaultValue = "-id") @Validated @Pattern(regexp = "^[-+][\\w]+") String order) {
+        return Result.ok(temporaryTaskExtService.selectReceiveList(status, page, size, order));
+    }
+
+    /**
+     * 我发出的任务列表
+     *
+     * @param status 任务状态 1:正在处理 2:已经完成 3:已经取消 4:超时任务
+     * @return 临时任务列表
+     * @since 1.0.2
+     */
+    @RequireLogin
+    @GetMapping("/list/publish")
+    @IgnorePermissionsCheck
+    public Result<PageInfo<TemporaryTaskVO>> listPublish(@RequestParam @Range(min = 1, max = 4) Integer status,
+                                                         @RequestParam(defaultValue = "1") Integer page,
+                                                         @RequestParam(defaultValue = "10") Integer size,
+                                                         @RequestParam(defaultValue = "-id") @Validated @Pattern(regexp = "^[-+][\\w]+") String order) {
+        return Result.ok(temporaryTaskExtService.selectPublishList(status, page, size, order));
+    }
+
+    /**
+     * 我收到的最新的一条任务
+     *
+     * @param status 任务状态 1:正在处理 2:已经完成 3:已经取消 4:超时任务 不传时查询所有任务
+     * @return 临时任务
+     * @since 1.0.2
+     */
+    @RequireLogin
+    @GetMapping("/query/newest")
+    @IgnorePermissionsCheck
+    public Result<TemporaryTaskVO> queryNewest(@RequestParam(required = false) @Range(min = 1, max = 4) Integer status) {
+        return Result.ok(temporaryTaskExtService.queryNewest(status));
+    }
+
+}

+ 39 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/controller/temporarytask/TemporaryTaskFeedbackExtController.java

@@ -0,0 +1,39 @@
+package com.chuanghai.patrol.controller.temporarytask;
+
+import com.chuanghai.patrol.entity.Result;
+import com.chuanghai.patrol.from.TemporaryTaskFeedbackAddFrom;
+import com.chuanghai.patrol.model.TemporaryTaskFeedback;
+import com.chuanghai.patrol.service.temporarytask.TemporaryTaskFeedbackExtService;
+import com.flyhigh.core.annotation.IgnorePermissionsCheck;
+import com.flyhigh.core.annotation.RequireLogin;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+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;
+
+/**
+ * 临时任务反馈
+ */
+@Validated
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/v1/temporary/task/feedback")
+public class TemporaryTaskFeedbackExtController {
+    private final TemporaryTaskFeedbackExtService temporaryTaskFeedbackExtService;
+
+    /**
+     * 添加临时任务反馈
+     *
+     * @param temporaryTaskFeedbackAddFrom 临时任务反馈
+     * @return 临时任务反馈
+     * @since 1.0.0
+     */
+    @RequireLogin
+    @PostMapping("/add")
+    @IgnorePermissionsCheck
+    public Result<TemporaryTaskFeedback> add(@RequestBody @Validated TemporaryTaskFeedbackAddFrom temporaryTaskFeedbackAddFrom) {
+        return Result.ok(temporaryTaskFeedbackExtService.add(temporaryTaskFeedbackAddFrom));
+    }
+}

+ 58 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/controller/visitor/VisitorAuditExtController.java

@@ -0,0 +1,58 @@
+package com.chuanghai.patrol.controller.visitor;
+
+import com.chuanghai.patrol.entity.Result;
+import com.chuanghai.patrol.from.VisitorAuditAddFrom;
+import com.chuanghai.patrol.from.VisitorAuditUpdateFrom;
+import com.chuanghai.patrol.service.visitor.VisitorAuditExtService;
+import com.chuanghai.patrol.vo.VisitorAuditVO;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 访客审批
+ */
+@Validated
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/v1/visitor/audit")
+public class VisitorAuditExtController {
+    private final VisitorAuditExtService visitorAuditExtService;
+
+    /**
+     * 进入登记
+     *
+     * @param visitorAuditAddFrom 访客
+     * @return 访客
+     * @since 1.0.2
+     */
+    @PostMapping("/add")
+    public Result<String> add(@RequestBody @Validated VisitorAuditAddFrom visitorAuditAddFrom) {
+        return Result.ok(visitorAuditExtService.add(visitorAuditAddFrom));
+    }
+
+    /**
+     * 查询进入记录
+     *
+     * @param openid 用户openid
+     * @return 进入记录
+     * @since 1.0.1
+     */
+    @GetMapping("/query/{openid}")
+    public Result<VisitorAuditVO> query(@PathVariable String openid) {
+        return Result.ok(visitorAuditExtService.query(openid));
+    }
+
+    /**
+     * 出场核销
+     *
+     * @param visitorAuditUpdateFrom 访客
+     * @return 访客
+     * @since 1.0.2
+     */
+    @PutMapping("/update")
+    public Result<String> update(@RequestBody @Validated VisitorAuditUpdateFrom visitorAuditUpdateFrom) {
+        return Result.ok(visitorAuditExtService.update(visitorAuditUpdateFrom));
+    }
+
+}

+ 32 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/controller/visitor/VisitorRegulationExtController.java

@@ -0,0 +1,32 @@
+package com.chuanghai.patrol.controller.visitor;
+
+import com.chuanghai.patrol.entity.Result;
+import com.chuanghai.patrol.model.VisitorRegulation;
+import com.chuanghai.patrol.service.visitor.VisitorRegulationExtService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 制度管理
+ */
+@Validated
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/v1/visitor/regulation")
+public class VisitorRegulationExtController {
+    private final VisitorRegulationExtService visitorRegulationExtService;
+
+    /**
+     * 查询制度
+     *
+     * @return 制度
+     * @since 1.0.1
+     */
+    @GetMapping("/query")
+    public Result<VisitorRegulation> query() {
+        return Result.ok(visitorRegulationExtService.query());
+    }
+}

+ 30 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/controller/wechat/WechatController.java

@@ -0,0 +1,30 @@
+package com.chuanghai.patrol.controller.wechat;
+
+import com.chuanghai.patrol.entity.Result;
+import com.chuanghai.patrol.util.wechat.WeChatUtil;
+import lombok.extern.slf4j.Slf4j;
+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;
+
+/**
+ * 微信小程序
+ */
+@Slf4j
+@RestController
+@RequestMapping(value = "/v1/wechat")
+public class WechatController {
+
+    /**
+     * 登录
+     *
+     * @param code 用户code
+     * @return openid
+     * @since 1.0.0
+     */
+    @GetMapping(value = "/login")
+    public Result<String> login(@RequestParam String code) {
+        return Result.ok(WeChatUtil.code2Session(code).getOpenid());
+    }
+}

+ 32 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/entity/PageInfo.java

@@ -0,0 +1,32 @@
+package com.chuanghai.patrol.entity;
+
+import com.github.pagehelper.PageSerializable;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 分页数据
+ */
+@Data
+@AllArgsConstructor
+public class PageInfo<T> {
+    /**
+     * 数据总数
+     */
+    private long total;
+
+    /**
+     * 数据列表
+     */
+    private List<T> list;
+
+    public static <T> PageInfo<T> of(long total, List<T> list) {
+        return new PageInfo<>(total, list);
+    }
+
+    public static <T> PageInfo<T> of(PageSerializable<T> pageSerializable) {
+        return new PageInfo<>(pageSerializable.getTotal(), pageSerializable.getList());
+    }
+}

+ 42 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/entity/Result.java

@@ -0,0 +1,42 @@
+package com.chuanghai.patrol.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.http.HttpStatus;
+
+/**
+ * 请求响应数据
+ *
+ * @param <T> 数据类型
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@SuppressWarnings("unused")
+public class Result<T> {
+    /**
+     * 数据
+     */
+    private T data;
+    /**
+     * 信息
+     */
+    private String message;
+    /**
+     * 状态码
+     */
+    private int code;
+
+    public static <T> Result<T> ok() {
+        return new Result<>(null, "", HttpStatus.SC_OK);
+    }
+
+    public static <T> Result<T> ok(T data) {
+        return new Result<>(data, "", HttpStatus.SC_OK);
+    }
+
+    public static <T> Result<T> ok(T data, String message) {
+        return new Result<>(data, message, HttpStatus.SC_OK);
+    }
+}

+ 24 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/from/PatrolTaskRecordItemFrom.java

@@ -0,0 +1,24 @@
+package com.chuanghai.patrol.from;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * 巡检任务检查项目表单
+ */
+@Data
+@AllArgsConstructor
+public class PatrolTaskRecordItemFrom {
+    /**
+     * 检查记录id
+     */
+    @NotNull
+    private Long id;
+
+    /**
+     * 记录值
+     */
+    private String value;
+}

+ 33 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/from/PatrolTaskRecordUpdateFrom.java

@@ -0,0 +1,33 @@
+package com.chuanghai.patrol.from;
+
+import lombok.Data;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+/**
+ * 巡检任务记录更新表单
+ */
+@Data
+public class PatrolTaskRecordUpdateFrom {
+    /**
+     * 任务id
+     */
+    @NotNull
+    private Long taskId;
+
+    /**
+     * 房间id
+     */
+    @NotNull
+    private Long roomId;
+
+    /**
+     * 巡检任务检查项目
+     * 例: [{"id": 79,"value": "480,482"}, {"id": 82,"value": 100}, {"id": 80,"value": "文本"},{"id": 81, "value": "[{\"id\": 74,\"value\": \"拍照\"}]"}]
+     */
+    @Valid
+    @NotNull
+    private List<PatrolTaskRecordItemFrom> items;
+}

+ 43 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/from/SystemUserCommentAddFrom.java

@@ -0,0 +1,43 @@
+package com.chuanghai.patrol.from;
+
+import lombok.Data;
+import org.hibernate.validator.constraints.Range;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+/**
+ * 用户评价添加表单
+ */
+@Data
+public class SystemUserCommentAddFrom {
+    /**
+     * 被评价人id
+     */
+    @NotNull
+    private Long respondentUserId;
+
+    /**
+     * 被评价人姓名
+     */
+    @NotBlank
+    private String respondentUsername;
+
+    /**
+     * 评论内容
+     */
+    @NotBlank
+    private String content;
+
+    /**
+     * 评论分数
+     */
+    @NotNull
+    @Range(min = 1, max = 5)
+    private Integer score;
+
+    /**
+     * 评论图片地址数组
+     */
+    private String images;
+}

+ 23 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/from/SystemUserLoginFrom.java

@@ -0,0 +1,23 @@
+package com.chuanghai.patrol.from;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * 用户登录表单
+ */
+@Data
+public class SystemUserLoginFrom {
+    /**
+     * 用户名
+     */
+    @NotBlank
+    private String username;
+
+    /**
+     * 用户密码(md5加密)
+     */
+    @NotBlank
+    private String password;
+}

+ 24 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/from/SystemUserPasswordUpdateFrom.java

@@ -0,0 +1,24 @@
+package com.chuanghai.patrol.from;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * 用户密码
+ */
+@Data
+public class SystemUserPasswordUpdateFrom {
+
+    /**
+     * 旧密码(md5加密)
+     */
+    @NotBlank
+    private String passwordOld;
+
+    /**
+     * 密码(md5加密)
+     */
+    @NotBlank
+    private String password;
+}

+ 68 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/from/TemporaryTaskAddFrom.java

@@ -0,0 +1,68 @@
+package com.chuanghai.patrol.from;
+
+import lombok.Data;
+import org.hibernate.validator.constraints.Range;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * 临时任务添加表单
+ */
+@Data
+public class TemporaryTaskAddFrom {
+    /**
+     * 任务标题
+     */
+    @NotBlank
+    @Size(max = 255)
+    private String title;
+
+    /**
+     * 房间id
+     */
+    @NotNull
+    private Long roomId;
+
+    /**
+     * 所属系统
+     */
+    @NotBlank
+    private String belongSystem;
+
+    /**
+     * 任务类型  1:一般任务 2: 较急任务 3:紧急任务
+     */
+    @NotNull
+    @Range(min = 1, max = 3)
+    private Integer type;
+
+    /**
+     * 任务内容
+     */
+    @NotBlank
+    @Size(max = 255)
+    private String content;
+
+    /**
+     * 执行人列表
+     */
+    @NotNull
+    @NotEmpty
+    private List<Long> executors;
+
+    /**
+     * 完成时间
+     */
+    @NotNull
+    private LocalDateTime finishTime;
+
+    /**
+     * 任务图片
+     */
+    private String images;
+}

+ 27 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/from/TemporaryTaskFeedbackAddFrom.java

@@ -0,0 +1,27 @@
+package com.chuanghai.patrol.from;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * 临时任务反馈添加表单
+ */
+@Data
+public class TemporaryTaskFeedbackAddFrom {
+    /**
+     * 任务id
+     */
+    @NotNull
+    private Long taskId;
+
+    /**
+     * 反馈内容
+     */
+    private String content;
+
+    /**
+     * 反馈图片
+     */
+    private String images;
+}

+ 30 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/from/TemporaryTaskStatusUpdateFrom.java

@@ -0,0 +1,30 @@
+package com.chuanghai.patrol.from;
+
+import lombok.Data;
+import org.hibernate.validator.constraints.Range;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * 临时任务状态更新表单
+ */
+@Data
+public class TemporaryTaskStatusUpdateFrom {
+    /**
+     * id 主键
+     */
+    @NotNull
+    private Long id;
+
+    /**
+     * 任务状态 1:完成 2:取消 3:不通过
+     */
+    @NotNull
+    @Range(min = 1, max = 3)
+    private Integer status;
+
+    /**
+     * 审核备注
+     */
+    private String remake;
+}

+ 70 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/from/VisitorAuditAddFrom.java

@@ -0,0 +1,70 @@
+package com.chuanghai.patrol.from;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+
+/**
+ * 访客添加表单
+ */
+@Data
+public class VisitorAuditAddFrom {
+    /**
+     * 用户openid
+     */
+    @NotBlank
+    private String openid;
+
+    /**
+     * 访客姓名
+     */
+    @NotBlank
+    private String username;
+
+    /**
+     * 访客手机号
+     */
+    @NotBlank
+    @Pattern(regexp = "^1[345789][0-9]\\d{8}$")
+    private String userPhone;
+
+    /**
+     * 访客公司
+     */
+    @NotBlank
+    private String company;
+
+    /**
+     * 访问时长(小时)
+     */
+    @NotNull
+    private Integer duration;
+
+    /**
+     * 行程码
+     */
+    private String itineraryCode;
+
+    /**
+     * 健康码
+     */
+    private String healthCode;
+
+    /**
+     * 是否高风险
+     */
+    private Boolean highRisk;
+
+    /**
+     * 事由
+     */
+    @NotBlank
+    private String reason;
+
+    /**
+     * 审核资料
+     */
+    private String information;
+}

+ 22 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/from/VisitorAuditUpdateFrom.java

@@ -0,0 +1,22 @@
+package com.chuanghai.patrol.from;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * 访客更新表单
+ */
+@Data
+public class VisitorAuditUpdateFrom {
+    /**
+     * 入场记录id
+     */
+    @NotNull
+    private Long id;
+
+    /**
+     * 出场备注
+     */
+    private String remark;
+}

+ 25 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/checkroute/CheckRouteExtService.java

@@ -0,0 +1,25 @@
+package com.chuanghai.patrol.service.checkroute;
+
+import com.chuanghai.patrol.service.mapper.checkroute.CheckRouteExtMapper;
+import com.chuanghai.patrol.vo.OptionVO;
+import com.flyhigh.core.ApplicationContext;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 检查路线服务
+ */
+@Service
+@RequiredArgsConstructor
+public class CheckRouteExtService extends ApplicationContext {
+    private final CheckRouteExtMapper patrolRouteExtMapper;
+
+    /**
+     * 路线选项列表
+     */
+    public List<OptionVO> selectOptionList(String name) {
+        return patrolRouteExtMapper.selectOptionListByRouteName(name);
+    }
+}

+ 68 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/common/FileService.java

@@ -0,0 +1,68 @@
+package com.chuanghai.patrol.service.common;
+
+import com.chuanghai.patrol.config.AppProperties;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.FileUtils;
+import org.springframework.stereotype.Service;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Date;
+
+/**
+ * 文件服务
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+@SuppressWarnings("unused")
+public class FileService {
+    private final AppProperties appProperties;
+
+    /**
+     * 获取文件
+     */
+    public File getFile(String relativePath) {
+        return new File(appProperties.getFilePath(), relativePath);
+    }
+
+    /**
+     * 删除文件或者目录
+     */
+    public void deleteFile(String file) {
+        try {
+            FileUtils.forceDelete(getFile(file));
+        } catch (IOException ex) {
+            log.error("delete file error: " + file + " {}", ex.getMessage());
+        }
+    }
+
+    /**
+     * 清理临时文件目录
+     *
+     * @param before 在这个时间之前的文件
+     */
+    public void clearCacheFiles(Date before) {
+        try {
+            File tempDir = new File(appProperties.getTempFilePath());
+            File[] childFiles = tempDir.listFiles();
+            if (childFiles != null && childFiles.length != 0) {
+                for (File file : childFiles) {
+                    if (file.lastModified() < before.getTime()) {
+                        FileUtils.forceDelete(file);
+                    }
+                }
+            }
+        } catch (IOException ex) {
+            log.error("clearCacheFiles error : {}", ex.getMessage());
+        }
+    }
+
+    /**
+     * 获取文件相对路径
+     */
+    public String getFileKey(File f) {
+        return f.getPath().replace(appProperties.getTempFilePath(), "");
+    }
+}

+ 25 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/device/DeviceBuildingExtService.java

@@ -0,0 +1,25 @@
+package com.chuanghai.patrol.service.device;
+
+import com.chuanghai.patrol.service.mapper.device.DeviceBuildingExtMapper;
+import com.chuanghai.patrol.vo.OptionVO;
+import com.flyhigh.core.ApplicationContext;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 楼栋服务
+ */
+@Service
+@RequiredArgsConstructor
+public class DeviceBuildingExtService extends ApplicationContext {
+    private final DeviceBuildingExtMapper deviceBuildingExtMapper;
+
+    /**
+     * 楼栋选项列表
+     */
+    public List<OptionVO> selectOptionList() {
+        return deviceBuildingExtMapper.selectOptionList();
+    }
+}

+ 27 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/device/DeviceExtService.java

@@ -0,0 +1,27 @@
+package com.chuanghai.patrol.service.device;
+
+import com.chuanghai.patrol.entity.PageInfo;
+import com.chuanghai.patrol.service.mapper.device.DeviceExtMapper;
+import com.chuanghai.patrol.vo.DeviceVO;
+import com.flyhigh.core.ApplicationContext;
+import com.github.pagehelper.PageHelper;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+/**
+ * 设备服务
+ */
+@Service
+@RequiredArgsConstructor
+public class DeviceExtService extends ApplicationContext {
+    private final DeviceExtMapper deviceExtMapper;
+
+    /**
+     * 分页查询设备
+     */
+    public PageInfo<DeviceVO> selectList(Long roomId, Integer page, Integer size) {
+        return PageInfo.of(PageHelper.startPage(page, size).doSelectPageSerializable(() ->
+                deviceExtMapper.selectList(roomId)
+        ));
+    }
+}

+ 25 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/device/DeviceFloorExtService.java

@@ -0,0 +1,25 @@
+package com.chuanghai.patrol.service.device;
+
+import com.chuanghai.patrol.service.mapper.device.DeviceFloorExtMapper;
+import com.chuanghai.patrol.vo.OptionVO;
+import com.flyhigh.core.ApplicationContext;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 楼层服务
+ */
+@Service
+@RequiredArgsConstructor
+public class DeviceFloorExtService extends ApplicationContext {
+    private final DeviceFloorExtMapper deviceFloorExtMapper;
+
+    /**
+     * 楼层选项列表
+     */
+    public List<OptionVO> selectOptionList(Long buildingId) {
+        return deviceFloorExtMapper.selectOptionListByBuildingId(buildingId);
+    }
+}

+ 56 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/device/DeviceRoomExtService.java

@@ -0,0 +1,56 @@
+package com.chuanghai.patrol.service.device;
+
+import com.chuanghai.patrol.entity.PageInfo;
+import com.chuanghai.patrol.model.CheckRoute;
+import com.chuanghai.patrol.service.mapper.checkitem.CheckItemExtMapper;
+import com.chuanghai.patrol.service.mapper.checkroute.CheckRouteExtMapper;
+import com.chuanghai.patrol.service.mapper.device.DeviceExtMapper;
+import com.chuanghai.patrol.service.mapper.device.DeviceRoomExtMapper;
+import com.chuanghai.patrol.vo.DeviceRoomDetailsVO;
+import com.chuanghai.patrol.vo.DeviceRoomOptionVO;
+import com.chuanghai.patrol.vo.OptionVO;
+import com.flyhigh.core.ApplicationContext;
+import com.flyhigh.core.exception.CustomizeException;
+import com.github.pagehelper.PageHelper;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 房间服务
+ */
+@Service
+@RequiredArgsConstructor
+public class DeviceRoomExtService extends ApplicationContext {
+    private final DeviceRoomExtMapper deviceRoomExtMapper;
+    private final CheckRouteExtMapper checkRouteExtMapper;
+    private final CheckItemExtMapper checkItemExtMapper;
+    private final DeviceExtMapper deviceExtMapper;
+
+    /**
+     * 获取巡检路线中的房间
+     */
+    public PageInfo<DeviceRoomOptionVO> selectList(String name, Long id, Integer page, Integer size) {
+        return PageInfo.of(PageHelper.startPage(page, size).doSelectPageSerializable(() -> deviceRoomExtMapper.selectListByRoute(name, id)));
+    }
+
+    /**
+     * 查询房间详情
+     */
+    public DeviceRoomDetailsVO query(Long id, Long routeId) {
+        DeviceRoomDetailsVO deviceRoomDetailsVO = deviceRoomExtMapper.selectById(id).orElseThrow(() -> CustomizeException.exceptionClient("房间不存在"));
+        CheckRoute checkRoute = checkRouteExtMapper.selectByPrimaryKey(routeId).orElseThrow(() -> CustomizeException.exceptionClient("路线不存在"));
+        deviceRoomDetailsVO.setRouteName(checkRoute.getName());
+        deviceRoomDetailsVO.setCheckItems(checkItemExtMapper.selectOptionListByRoomAndRoute(id));
+        deviceRoomDetailsVO.setDevices(deviceExtMapper.selectListByRoomAndRoute(id));
+        return deviceRoomDetailsVO;
+    }
+
+    /**
+     * 房间选项列表
+     */
+    public List<OptionVO> selectOptionList(Long floorId) {
+        return deviceRoomExtMapper.selectOptionListByFloorId(floorId);
+    }
+}

+ 36 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/checkitem/CheckItemExtMapper.java

@@ -0,0 +1,36 @@
+package com.chuanghai.patrol.service.mapper.checkitem;
+
+import com.chuanghai.patrol.dao.CheckItemDynamicSqlSupport;
+import com.chuanghai.patrol.dao.CheckItemMapper;
+import com.chuanghai.patrol.dao.DeviceRoomAndCheckItemDynamicSqlSupport;
+import com.chuanghai.patrol.vo.CheckItemOptionVO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.SelectProvider;
+import org.mybatis.dynamic.sql.SqlBuilder;
+import org.mybatis.dynamic.sql.render.RenderingStrategies;
+import org.mybatis.dynamic.sql.select.render.SelectStatementProvider;
+import org.mybatis.dynamic.sql.util.SqlProviderAdapter;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+import java.util.List;
+
+import static org.mybatis.dynamic.sql.SqlBuilder.equalTo;
+import static org.mybatis.dynamic.sql.SqlBuilder.isEqualTo;
+
+@Mapper
+public interface CheckItemExtMapper extends CheckItemMapper, CommonSelectMapper {
+    @SelectProvider(type = SqlProviderAdapter.class, method = "select")
+    List<CheckItemOptionVO> selectOptionListByRoomAndRoute(SelectStatementProvider selectStatement);
+
+    /**
+     * 根据房间查询检查项
+     */
+    default List<CheckItemOptionVO> selectOptionListByRoomAndRoute(Long id) {
+        SelectStatementProvider selectStatement = SqlBuilder.select(CheckItemDynamicSqlSupport.id, CheckItemDynamicSqlSupport.itemName.as("name"), CheckItemDynamicSqlSupport.itemType)
+                .from(CheckItemDynamicSqlSupport.checkItem)
+                .join(DeviceRoomAndCheckItemDynamicSqlSupport.deviceRoomAndCheckItem).on(DeviceRoomAndCheckItemDynamicSqlSupport.checkItemId, equalTo(CheckItemDynamicSqlSupport.id))
+                .where(DeviceRoomAndCheckItemDynamicSqlSupport.roomId, isEqualTo(id))
+                .build().render(RenderingStrategies.MYBATIS3);
+        return selectOptionListByRoomAndRoute(selectStatement);
+    }
+}

+ 9 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/checkitem/CheckItemTypeExtMapper.java

@@ -0,0 +1,9 @@
+package com.chuanghai.patrol.service.mapper.checkitem;
+
+import com.chuanghai.patrol.dao.CheckItemTypeMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+@Mapper
+public interface CheckItemTypeExtMapper extends CheckItemTypeMapper, CommonSelectMapper {
+}

+ 35 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/checkroute/CheckRouteExtMapper.java

@@ -0,0 +1,35 @@
+package com.chuanghai.patrol.service.mapper.checkroute;
+
+import com.chuanghai.patrol.dao.CheckRouteDynamicSqlSupport;
+import com.chuanghai.patrol.dao.CheckRouteMapper;
+import com.chuanghai.patrol.vo.OptionVO;
+import com.flyhigh.core.mybatis.SqlExtBuilder;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.SelectProvider;
+import org.mybatis.dynamic.sql.SqlBuilder;
+import org.mybatis.dynamic.sql.render.RenderingStrategies;
+import org.mybatis.dynamic.sql.select.render.SelectStatementProvider;
+import org.mybatis.dynamic.sql.util.SqlProviderAdapter;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+import java.util.List;
+
+import static com.flyhigh.core.mybatis.SqlExtBuilder.isLikeAll;
+
+@Mapper
+public interface CheckRouteExtMapper extends CheckRouteMapper, CommonSelectMapper {
+    @SelectProvider(type = SqlProviderAdapter.class, method = "select")
+    List<OptionVO> selectOptionListByRouteName(SelectStatementProvider selectStatement);
+
+    /**
+     * 路线选项
+     */
+    default List<OptionVO> selectOptionListByRouteName(String name) {
+        SelectStatementProvider selectStatement = SqlBuilder.select(CheckRouteDynamicSqlSupport.id, CheckRouteDynamicSqlSupport.name)
+                .from(CheckRouteDynamicSqlSupport.checkRoute)
+                .where(CheckRouteDynamicSqlSupport.name, isLikeAll(name).filter(SqlExtBuilder.isNonEmpty()))
+                .orderBy(CheckRouteDynamicSqlSupport.name)
+                .build().render(RenderingStrategies.MYBATIS3);
+        return selectOptionListByRouteName(selectStatement);
+    }
+}

+ 9 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/device/DeviceAndCheckItemExtMapper.java

@@ -0,0 +1,9 @@
+package com.chuanghai.patrol.service.mapper.device;
+
+import com.chuanghai.patrol.dao.DeviceAndCheckItemMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+@Mapper
+public interface DeviceAndCheckItemExtMapper extends DeviceAndCheckItemMapper, CommonSelectMapper {
+}

+ 29 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/device/DeviceBuildingExtMapper.java

@@ -0,0 +1,29 @@
+package com.chuanghai.patrol.service.mapper.device;
+
+import com.chuanghai.patrol.dao.DeviceBuildingDynamicSqlSupport;
+import com.chuanghai.patrol.dao.DeviceBuildingMapper;
+import com.chuanghai.patrol.vo.OptionVO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.SelectProvider;
+import org.mybatis.dynamic.sql.SqlBuilder;
+import org.mybatis.dynamic.sql.render.RenderingStrategies;
+import org.mybatis.dynamic.sql.select.render.SelectStatementProvider;
+import org.mybatis.dynamic.sql.util.SqlProviderAdapter;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+import java.util.List;
+
+@Mapper
+public interface DeviceBuildingExtMapper extends DeviceBuildingMapper, CommonSelectMapper {
+
+    @SelectProvider(type = SqlProviderAdapter.class, method = "select")
+    List<OptionVO> selectOptionList(SelectStatementProvider selectStatement);
+
+    /**
+     * 楼栋选项列表
+     */
+    default List<OptionVO> selectOptionList() {
+        SelectStatementProvider selectStatement = SqlBuilder.select(DeviceBuildingDynamicSqlSupport.id, DeviceBuildingDynamicSqlSupport.name).from(DeviceBuildingDynamicSqlSupport.deviceBuilding).build().render(RenderingStrategies.MYBATIS3);
+        return selectOptionList(selectStatement);
+    }
+}

+ 9 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/device/DeviceCabinetChildDeviceExtMapper.java

@@ -0,0 +1,9 @@
+package com.chuanghai.patrol.service.mapper.device;
+
+import com.chuanghai.patrol.dao.DeviceCabinetChildDeviceMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+@Mapper
+public interface DeviceCabinetChildDeviceExtMapper extends DeviceCabinetChildDeviceMapper, CommonSelectMapper {
+}

+ 9 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/device/DeviceCabinetLogExtMapper.java

@@ -0,0 +1,9 @@
+package com.chuanghai.patrol.service.mapper.device;
+
+import com.chuanghai.patrol.dao.DeviceCabinetLogMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+@Mapper
+public interface DeviceCabinetLogExtMapper extends DeviceCabinetLogMapper, CommonSelectMapper {
+}

+ 65 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/device/DeviceExtMapper.java

@@ -0,0 +1,65 @@
+package com.chuanghai.patrol.service.mapper.device;
+
+import com.chuanghai.patrol.dao.CheckItemDynamicSqlSupport;
+import com.chuanghai.patrol.dao.DeviceAndCheckItemDynamicSqlSupport;
+import com.chuanghai.patrol.dao.DeviceDynamicSqlSupport;
+import com.chuanghai.patrol.dao.DeviceMapper;
+import com.chuanghai.patrol.vo.DeviceDetailsVO;
+import com.chuanghai.patrol.vo.DeviceVO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.ResultMap;
+import org.apache.ibatis.annotations.SelectProvider;
+import org.mybatis.dynamic.sql.SqlBuilder;
+import org.mybatis.dynamic.sql.render.RenderingStrategies;
+import org.mybatis.dynamic.sql.select.render.SelectStatementProvider;
+import org.mybatis.dynamic.sql.util.SqlProviderAdapter;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+import java.util.List;
+
+import static org.mybatis.dynamic.sql.SqlBuilder.equalTo;
+import static org.mybatis.dynamic.sql.SqlBuilder.isEqualTo;
+
+@Mapper
+public interface DeviceExtMapper extends DeviceMapper, CommonSelectMapper {
+
+    @ResultMap("deviceDetails")
+    @SelectProvider(type = SqlProviderAdapter.class, method = "select")
+    List<DeviceDetailsVO> selectListByRoomAndRoute(SelectStatementProvider selectStatement);
+
+    /**
+     * 根据房间和路线查询设备详情
+     */
+    default List<DeviceDetailsVO> selectListByRoomAndRoute(Long id) {
+        SelectStatementProvider statementProvider = SqlBuilder.select(
+                        DeviceDynamicSqlSupport.id,
+                        DeviceDynamicSqlSupport.name,
+                        CheckItemDynamicSqlSupport.id.as("check_item_id"),
+                        CheckItemDynamicSqlSupport.itemName,
+                        CheckItemDynamicSqlSupport.itemType)
+                .from(DeviceDynamicSqlSupport.device)
+                .leftJoin(DeviceAndCheckItemDynamicSqlSupport.deviceAndCheckItem).on(DeviceAndCheckItemDynamicSqlSupport.deviceId, equalTo(DeviceDynamicSqlSupport.id))
+                .leftJoin(CheckItemDynamicSqlSupport.checkItem).on(CheckItemDynamicSqlSupport.id, equalTo(DeviceAndCheckItemDynamicSqlSupport.checkItemId))
+                .where(DeviceDynamicSqlSupport.roomId, isEqualTo(id))
+                .groupBy(DeviceDynamicSqlSupport.id, CheckItemDynamicSqlSupport.id)
+                .build().render(RenderingStrategies.MYBATIS3);
+        return selectListByRoomAndRoute(statementProvider);
+    }
+
+    @SelectProvider(type = SqlProviderAdapter.class, method = "select")
+    List<DeviceVO> selectList(SelectStatementProvider selectStatement);
+
+    /**
+     * 设备列表
+     */
+    default List<DeviceVO> selectList(Long roomId) {
+        SelectStatementProvider statementProvider = SqlBuilder.select(DeviceDynamicSqlSupport.id, DeviceDynamicSqlSupport.name, DeviceDynamicSqlSupport.number, DeviceDynamicSqlSupport.type,
+                        SqlBuilder.countDistinct(DeviceAndCheckItemDynamicSqlSupport.id).as("check_item_total"))
+                .from(DeviceDynamicSqlSupport.device)
+                .leftJoin(DeviceAndCheckItemDynamicSqlSupport.deviceAndCheckItem).on(DeviceAndCheckItemDynamicSqlSupport.deviceId, equalTo(DeviceDynamicSqlSupport.id))
+                .where(DeviceDynamicSqlSupport.roomId, isEqualTo(roomId))
+                .groupBy(DeviceDynamicSqlSupport.id)
+                .build().render(RenderingStrategies.MYBATIS3);
+        return selectList(statementProvider);
+    }
+}

+ 9 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/device/DeviceExtraOfCabinetExtMapper.java

@@ -0,0 +1,9 @@
+package com.chuanghai.patrol.service.mapper.device;
+
+import com.chuanghai.patrol.dao.DeviceExtraOfCabinetMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+@Mapper
+public interface DeviceExtraOfCabinetExtMapper extends DeviceExtraOfCabinetMapper, CommonSelectMapper {
+}

+ 34 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/device/DeviceFloorExtMapper.java

@@ -0,0 +1,34 @@
+package com.chuanghai.patrol.service.mapper.device;
+
+import com.chuanghai.patrol.dao.DeviceFloorDynamicSqlSupport;
+import com.chuanghai.patrol.dao.DeviceFloorMapper;
+import com.chuanghai.patrol.vo.OptionVO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.SelectProvider;
+import org.mybatis.dynamic.sql.SqlBuilder;
+import org.mybatis.dynamic.sql.render.RenderingStrategies;
+import org.mybatis.dynamic.sql.select.render.SelectStatementProvider;
+import org.mybatis.dynamic.sql.util.SqlProviderAdapter;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+import java.util.List;
+
+import static org.mybatis.dynamic.sql.SqlBuilder.isEqualTo;
+
+@Mapper
+public interface DeviceFloorExtMapper extends DeviceFloorMapper, CommonSelectMapper {
+
+    @SelectProvider(type = SqlProviderAdapter.class, method = "select")
+    List<OptionVO> selectOptionListByBuildingId(SelectStatementProvider selectStatement);
+
+    /**
+     * 楼层选项列表
+     */
+    default List<OptionVO> selectOptionListByBuildingId(Long buildingId) {
+        SelectStatementProvider selectStatement = SqlBuilder.select(DeviceFloorDynamicSqlSupport.id, DeviceFloorDynamicSqlSupport.name)
+                .from(DeviceFloorDynamicSqlSupport.deviceFloor)
+                .where(DeviceFloorDynamicSqlSupport.buildingId, isEqualTo(buildingId))
+                .build().render(RenderingStrategies.MYBATIS3);
+        return selectOptionListByBuildingId(selectStatement);
+    }
+}

+ 9 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/device/DeviceRoomAndCheckItemExtMapper.java

@@ -0,0 +1,9 @@
+package com.chuanghai.patrol.service.mapper.device;
+
+import com.chuanghai.patrol.dao.DeviceRoomAndCheckItemMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+@Mapper
+public interface DeviceRoomAndCheckItemExtMapper extends DeviceRoomAndCheckItemMapper, CommonSelectMapper {
+}

+ 84 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/device/DeviceRoomExtMapper.java

@@ -0,0 +1,84 @@
+package com.chuanghai.patrol.service.mapper.device;
+
+import com.chuanghai.patrol.dao.*;
+import com.chuanghai.patrol.vo.DeviceRoomDetailsVO;
+import com.chuanghai.patrol.vo.DeviceRoomOptionVO;
+import com.chuanghai.patrol.vo.OptionVO;
+import com.flyhigh.core.mybatis.SqlExtBuilder;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.SelectProvider;
+import org.mybatis.dynamic.sql.SqlBuilder;
+import org.mybatis.dynamic.sql.render.RenderingStrategies;
+import org.mybatis.dynamic.sql.select.render.SelectStatementProvider;
+import org.mybatis.dynamic.sql.util.SqlProviderAdapter;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+import java.util.List;
+import java.util.Optional;
+
+import static org.mybatis.dynamic.sql.SqlBuilder.equalTo;
+import static org.mybatis.dynamic.sql.SqlBuilder.isEqualTo;
+
+@Mapper
+public interface DeviceRoomExtMapper extends DeviceRoomMapper, CommonSelectMapper {
+    @SelectProvider(type = SqlProviderAdapter.class, method = "select")
+    List<DeviceRoomOptionVO> selectListByRoute(SelectStatementProvider selectStatement);
+
+    /**
+     * 巡检路线中的房间
+     */
+    default List<DeviceRoomOptionVO> selectListByRoute(String name, Long id) {
+        SelectStatementProvider selectStatement = SqlBuilder.select(
+                        DeviceRoomDynamicSqlSupport.id,
+                        DeviceRoomDynamicSqlSupport.name,
+                        DeviceRoomDynamicSqlSupport.number,
+                        CheckRouteAndDeviceRoomDynamicSqlSupport.routeId)
+                .from(DeviceRoomDynamicSqlSupport.deviceRoom)
+                .join(CheckRouteAndDeviceRoomDynamicSqlSupport.checkRouteAndDeviceRoom).on(CheckRouteAndDeviceRoomDynamicSqlSupport.roomId, equalTo(DeviceRoomDynamicSqlSupport.id))
+                .where(DeviceRoomDynamicSqlSupport.name, SqlExtBuilder.isLikeAll(name).filter(SqlExtBuilder.isNonEmpty()))
+                .and(CheckRouteAndDeviceRoomDynamicSqlSupport.routeId, isEqualTo(id).filter(SqlExtBuilder.isNonEmpty()))
+                .union().select(DeviceRoomDynamicSqlSupport.id,
+                        DeviceRoomDynamicSqlSupport.name,
+                        DeviceRoomDynamicSqlSupport.number,
+                        CheckRouteAndDeviceDynamicSqlSupport.routeId)
+                .from(DeviceDynamicSqlSupport.device)
+                .join(DeviceRoomDynamicSqlSupport.deviceRoom).on(DeviceRoomDynamicSqlSupport.id, equalTo(DeviceDynamicSqlSupport.roomId))
+                .join(CheckRouteAndDeviceDynamicSqlSupport.checkRouteAndDevice).on(CheckRouteAndDeviceDynamicSqlSupport.deviceId, equalTo(DeviceDynamicSqlSupport.id))
+                .where(DeviceRoomDynamicSqlSupport.name, SqlExtBuilder.isLikeAll(name).filter(SqlExtBuilder.isNonEmpty()))
+                .and(CheckRouteAndDeviceDynamicSqlSupport.routeId, isEqualTo(id).filter(SqlExtBuilder.isNonEmpty()))
+                .build().render(RenderingStrategies.MYBATIS3);
+        return selectListByRoute(selectStatement);
+    }
+
+    @SelectProvider(type = SqlProviderAdapter.class, method = "select")
+    Optional<DeviceRoomDetailsVO> selectById(SelectStatementProvider selectStatement);
+
+    /**
+     * 房间详情
+     */
+    default Optional<DeviceRoomDetailsVO> selectById(Long id) {
+        SelectStatementProvider statementProvider = SqlBuilder.select(DeviceRoomDynamicSqlSupport.id, DeviceRoomDynamicSqlSupport.name, DeviceRoomDynamicSqlSupport.number,
+                        DeviceFloorDynamicSqlSupport.name.as("floor_name"),
+                        DeviceBuildingDynamicSqlSupport.name.as("building_name"))
+                .from(DeviceRoomDynamicSqlSupport.deviceRoom)
+                .leftJoin(DeviceFloorDynamicSqlSupport.deviceFloor).on(DeviceRoomDynamicSqlSupport.floorId, equalTo(DeviceFloorDynamicSqlSupport.id))
+                .leftJoin(DeviceBuildingDynamicSqlSupport.deviceBuilding).on(DeviceFloorDynamicSqlSupport.buildingId, equalTo(DeviceBuildingDynamicSqlSupport.id))
+                .where(DeviceRoomDynamicSqlSupport.id, isEqualTo(id))
+                .build().render(RenderingStrategies.MYBATIS3);
+        return selectById(statementProvider);
+    }
+
+    @SelectProvider(type = SqlProviderAdapter.class, method = "select")
+    List<OptionVO> selectOptionListByFloorId(SelectStatementProvider selectStatement);
+
+    /**
+     * 房间选项列表
+     */
+    default List<OptionVO> selectOptionListByFloorId(Long floorId) {
+        SelectStatementProvider selectStatement = SqlBuilder.select(DeviceRoomDynamicSqlSupport.id, DeviceRoomDynamicSqlSupport.name)
+                .from(DeviceRoomDynamicSqlSupport.deviceRoom)
+                .where(DeviceRoomDynamicSqlSupport.floorId, isEqualTo(floorId))
+                .build().render(RenderingStrategies.MYBATIS3);
+        return selectOptionListByFloorId(selectStatement);
+    }
+}

+ 9 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/device/DeviceTemplateExtMapper.java

@@ -0,0 +1,9 @@
+package com.chuanghai.patrol.service.mapper.device;
+
+import com.chuanghai.patrol.dao.DeviceTemplateMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+@Mapper
+public interface DeviceTemplateExtMapper extends DeviceTemplateMapper, CommonSelectMapper {
+}

+ 9 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/patrol/PatrolPlanAndSystemUserExtMapper.java

@@ -0,0 +1,9 @@
+package com.chuanghai.patrol.service.mapper.patrol;
+
+import com.chuanghai.patrol.dao.PatrolPlanAndSystemUserMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+@Mapper
+public interface PatrolPlanAndSystemUserExtMapper extends PatrolPlanAndSystemUserMapper, CommonSelectMapper {
+}

+ 9 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/patrol/PatrolPlanExtMapper.java

@@ -0,0 +1,9 @@
+package com.chuanghai.patrol.service.mapper.patrol;
+
+import com.chuanghai.patrol.dao.PatrolPlanMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+@Mapper
+public interface PatrolPlanExtMapper extends PatrolPlanMapper, CommonSelectMapper {
+}

+ 9 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/patrol/PatrolTaskAndSystemUserExtMapper.java

@@ -0,0 +1,9 @@
+package com.chuanghai.patrol.service.mapper.patrol;
+
+import com.chuanghai.patrol.dao.PatrolTaskAndSystemUserMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+@Mapper
+public interface PatrolTaskAndSystemUserExtMapper extends PatrolTaskAndSystemUserMapper, CommonSelectMapper {
+}

+ 430 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/patrol/PatrolTaskExtMapper.java

@@ -0,0 +1,430 @@
+package com.chuanghai.patrol.service.mapper.patrol;
+
+import com.chuanghai.patrol.dao.PatrolTaskDynamicSqlSupport;
+import com.chuanghai.patrol.dao.PatrolTaskMapper;
+import com.chuanghai.patrol.dao.PatrolTaskRecordDynamicSqlSupport;
+import com.chuanghai.patrol.vo.*;
+import com.flyhigh.core.mybatis.SqlExtBuilder;
+import com.flyhigh.core.mybatis.sql.If;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.ResultMap;
+import org.apache.ibatis.annotations.SelectProvider;
+import org.mybatis.dynamic.sql.Constant;
+import org.mybatis.dynamic.sql.DerivedColumn;
+import org.mybatis.dynamic.sql.SqlBuilder;
+import org.mybatis.dynamic.sql.render.RenderingStrategies;
+import org.mybatis.dynamic.sql.select.render.SelectStatementProvider;
+import org.mybatis.dynamic.sql.util.SqlProviderAdapter;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import static com.chuanghai.patrol.config.AppConstant.*;
+import static com.flyhigh.core.mybatis.SqlExtBuilder.isLikeAll;
+import static org.mybatis.dynamic.sql.SqlBuilder.*;
+
+@Mapper
+public interface PatrolTaskExtMapper extends PatrolTaskMapper, CommonSelectMapper {
+    /**
+     * 查询巡检任务id
+     */
+    default List<Long> selectTaskIdList(LocalDateTime beginTimeStart, LocalDateTime beginTimeEnd) {
+        SelectStatementProvider statementProvider = SqlBuilder.select(PatrolTaskDynamicSqlSupport.id, PatrolTaskDynamicSqlSupport.beginTime)
+                .from(PatrolTaskDynamicSqlSupport.patrolTask)
+                .where(PatrolTaskDynamicSqlSupport.status, isNotEqualTo(TASK_STATE_NOT_STARTED))
+                .and(PatrolTaskDynamicSqlSupport.beginTime, isGreaterThanOrEqualTo(beginTimeStart).filter(SqlExtBuilder.isNonEmpty()))
+                .and(PatrolTaskDynamicSqlSupport.beginTime, isLessThanOrEqualTo(beginTimeEnd).filter(SqlExtBuilder.isNonEmpty()))
+                .orderBy(PatrolTaskDynamicSqlSupport.beginTime.descending())
+                .build().render(RenderingStrategies.MYBATIS3);
+        return selectManyLongs(statementProvider);
+    }
+
+    @SelectProvider(type = SqlProviderAdapter.class, method = "select")
+    List<PatrolTaskVO> selectList(SelectStatementProvider selectStatement);
+
+    /**
+     * 查询巡检任务
+     */
+    default List<PatrolTaskVO> selectList(List<Long> ids) {
+        SelectStatementProvider statementProvider = SqlBuilder.select(
+                        PatrolTaskDynamicSqlSupport.id,
+                        PatrolTaskDynamicSqlSupport.status,
+                        PatrolTaskDynamicSqlSupport.name,
+                        PatrolTaskDynamicSqlSupport.beginTime,
+                        PatrolTaskDynamicSqlSupport.endTime,
+                        countDistinct(PatrolTaskRecordDynamicSqlSupport.roomId).as("total").as("total"),
+                        SqlExtBuilder.ifNull(DerivedColumn.of("completed_count"), 0).as("completed"),
+                        SqlBuilder.divide(SqlExtBuilder.ifNull(DerivedColumn.of("completed_count"), 0), countDistinct(PatrolTaskRecordDynamicSqlSupport.roomId)).as("completion_rate"))
+                .from(PatrolTaskDynamicSqlSupport.patrolTask, "pt")
+                .leftJoin(PatrolTaskRecordDynamicSqlSupport.patrolTaskRecord, "ptr").on(PatrolTaskRecordDynamicSqlSupport.taskId, equalTo(PatrolTaskDynamicSqlSupport.id))
+                .leftJoin(
+                        // 任务中已完成的房间数
+                        SqlBuilder.select(PatrolTaskRecordDynamicSqlSupport.taskId, countDistinct(PatrolTaskRecordDynamicSqlSupport.roomId).as("completed_count"))
+                                .from(PatrolTaskRecordDynamicSqlSupport.patrolTaskRecord)
+                                .where(PatrolTaskRecordDynamicSqlSupport.completed, isTrue())
+                                .and(PatrolTaskRecordDynamicSqlSupport.taskId, isIn(ids))
+                                .groupBy(PatrolTaskRecordDynamicSqlSupport.taskId)
+                        , "completed")
+                .on(PatrolTaskRecordDynamicSqlSupport.taskId.qualifiedWith("completed"), equalTo(PatrolTaskRecordDynamicSqlSupport.taskId))
+                .where(PatrolTaskDynamicSqlSupport.id, isIn(ids))
+                .groupBy(PatrolTaskDynamicSqlSupport.id)
+                .orderBy(PatrolTaskDynamicSqlSupport.beginTime.descending())
+                .build().render(RenderingStrategies.MYBATIS3);
+        return selectList(statementProvider);
+    }
+
+    /**
+     * 根据房间id查询正在进行的巡检任务id
+     */
+    default List<Long> selectTaskIdListByRoomId(Long userId, Long roomId) {
+        SelectStatementProvider statementProvider = SqlBuilder.select(PatrolTaskDynamicSqlSupport.id)
+                .from(PatrolTaskDynamicSqlSupport.patrolTask)
+                .join(PatrolTaskRecordDynamicSqlSupport.patrolTaskRecord).on(PatrolTaskRecordDynamicSqlSupport.taskId, equalTo(PatrolTaskDynamicSqlSupport.id))
+                .where(PatrolTaskDynamicSqlSupport.status, isEqualTo(TASK_STATE_PROCESSING))
+                .and(PatrolTaskRecordDynamicSqlSupport.completed, isFalse())
+                .and(PatrolTaskRecordDynamicSqlSupport.userId, isEqualTo(userId))
+                .and(PatrolTaskRecordDynamicSqlSupport.roomId, isEqualTo(roomId))
+                .groupBy(PatrolTaskDynamicSqlSupport.id)
+                .build().render(RenderingStrategies.MYBATIS3);
+        return selectManyLongs(statementProvider);
+    }
+
+    /**
+     * 查询正在进行的巡检任务
+     */
+    default List<PatrolTaskVO> selectTaskListByIds(Long userId, List<Long> ids) {
+        SelectStatementProvider statementProvider = SqlBuilder.select(
+                        PatrolTaskDynamicSqlSupport.id,
+                        PatrolTaskDynamicSqlSupport.name,
+                        PatrolTaskDynamicSqlSupport.status,
+                        PatrolTaskDynamicSqlSupport.beginTime,
+                        PatrolTaskDynamicSqlSupport.endTime,
+                        countDistinct(PatrolTaskRecordDynamicSqlSupport.roomId).as("total").as("total"),
+                        SqlExtBuilder.ifNull(DerivedColumn.of("completed_count"), 0).as("completed"),
+                        SqlBuilder.divide(SqlExtBuilder.ifNull(DerivedColumn.of("completed_count"), 0), countDistinct(PatrolTaskRecordDynamicSqlSupport.roomId)).as("completion_rate"))
+                .from(PatrolTaskDynamicSqlSupport.patrolTask, "pt")
+                .join(PatrolTaskRecordDynamicSqlSupport.patrolTaskRecord, "ptr").on(PatrolTaskRecordDynamicSqlSupport.taskId, equalTo(PatrolTaskDynamicSqlSupport.id))
+                .leftJoin(
+                        // 任务中已完成的房间数
+                        SqlBuilder.select(PatrolTaskRecordDynamicSqlSupport.taskId, countDistinct(PatrolTaskRecordDynamicSqlSupport.roomId).as("completed_count"))
+                                .from(PatrolTaskRecordDynamicSqlSupport.patrolTaskRecord)
+                                .where(PatrolTaskRecordDynamicSqlSupport.taskId, isIn(ids))
+                                .and(PatrolTaskRecordDynamicSqlSupport.userId, isEqualTo(userId))
+                                .and(PatrolTaskRecordDynamicSqlSupport.completed, isTrue())
+                                .groupBy(PatrolTaskRecordDynamicSqlSupport.taskId)
+                        , "completed")
+                .on(PatrolTaskRecordDynamicSqlSupport.taskId.qualifiedWith("completed"), equalTo(PatrolTaskRecordDynamicSqlSupport.taskId))
+                .where(PatrolTaskDynamicSqlSupport.id, isIn(ids))
+                .and(PatrolTaskRecordDynamicSqlSupport.userId, isEqualTo(userId))
+                .groupBy(PatrolTaskDynamicSqlSupport.id)
+                .build().render(RenderingStrategies.MYBATIS3);
+        return selectList(statementProvider);
+    }
+
+    @SelectProvider(type = SqlProviderAdapter.class, method = "select")
+    Optional<PatrolRoomDetailsVO> selectByUserTaskRoomId(SelectStatementProvider selectStatement);
+
+    /**
+     * 巡检任务
+     */
+    default Optional<PatrolRoomDetailsVO> selectByUserTaskRoomId(Long userId, Long taskId, Long roomId) {
+        SelectStatementProvider statementProvider = SqlBuilder.select(
+                        PatrolTaskRecordDynamicSqlSupport.roomId.as("id"),
+                        PatrolTaskRecordDynamicSqlSupport.roomName.as("name"),
+                        PatrolTaskRecordDynamicSqlSupport.roomNumber,
+                        PatrolTaskRecordDynamicSqlSupport.floorName,
+                        PatrolTaskRecordDynamicSqlSupport.buildingName,
+                        PatrolTaskDynamicSqlSupport.name.as("task_name"))
+                .from(PatrolTaskDynamicSqlSupport.patrolTask)
+                .leftJoin(PatrolTaskRecordDynamicSqlSupport.patrolTaskRecord).on(PatrolTaskRecordDynamicSqlSupport.taskId, equalTo(PatrolTaskDynamicSqlSupport.id))
+                .where(PatrolTaskRecordDynamicSqlSupport.userId, isEqualTo(userId))
+                .and(PatrolTaskRecordDynamicSqlSupport.roomId, isEqualTo(roomId))
+                .and(PatrolTaskDynamicSqlSupport.id, isEqualTo(taskId))
+                .groupBy(PatrolTaskRecordDynamicSqlSupport.roomId,
+                        PatrolTaskRecordDynamicSqlSupport.roomName,
+                        PatrolTaskRecordDynamicSqlSupport.roomNumber,
+                        PatrolTaskRecordDynamicSqlSupport.floorName,
+                        PatrolTaskRecordDynamicSqlSupport.buildingName,
+                        PatrolTaskDynamicSqlSupport.name)
+                .build().render(RenderingStrategies.MYBATIS3);
+        return selectByUserTaskRoomId(statementProvider);
+    }
+
+    @ResultMap("taskRate")
+    @SelectProvider(type = SqlProviderAdapter.class, method = "select")
+    Optional<PatrolRateVO> selectRateByUserTaskRoomId(SelectStatementProvider selectStatement);
+
+    /**
+     * 查询巡检任务
+     */
+    default Optional<PatrolRateVO> selectRateByUserTaskRoomId(Long id) {
+        SelectStatementProvider statementProvider = SqlBuilder.select(
+                        PatrolTaskDynamicSqlSupport.id,
+                        PatrolTaskDynamicSqlSupport.name,
+                        PatrolTaskDynamicSqlSupport.beginTime,
+                        PatrolTaskDynamicSqlSupport.endTime,
+                        DerivedColumn.of("total", "room_total").as("total"),
+                        SqlExtBuilder.ifNull(DerivedColumn.of("completed_count"), 0).as("completed"),
+                        SqlBuilder.divide(SqlExtBuilder.ifNull(DerivedColumn.of("completed_count"), 0), DerivedColumn.of("total", "room_total")).as("completion_rate"),
+                        PatrolTaskRecordDynamicSqlSupport.roomId,
+                        PatrolTaskRecordDynamicSqlSupport.roomName,
+                        PatrolTaskRecordDynamicSqlSupport.roomNumber,
+                        PatrolTaskRecordDynamicSqlSupport.completed.as("room_completed"),
+                        If.of(PatrolTaskRecordDynamicSqlSupport.roomId.qualifiedWith("qualified"), ">", Constant.of("0"), 0, 1).as("qualified"))
+                .from(PatrolTaskDynamicSqlSupport.patrolTask, "pt")
+                .join(PatrolTaskRecordDynamicSqlSupport.patrolTaskRecord, "ptr").on(PatrolTaskRecordDynamicSqlSupport.taskId, equalTo(PatrolTaskDynamicSqlSupport.id))
+                .leftJoin(
+                        // 任务中已完成的房间数
+                        SqlBuilder.select(PatrolTaskRecordDynamicSqlSupport.taskId, countDistinct(PatrolTaskRecordDynamicSqlSupport.roomId).as("completed_count"))
+                                .from(PatrolTaskRecordDynamicSqlSupport.patrolTaskRecord)
+                                .where(PatrolTaskRecordDynamicSqlSupport.taskId, isEqualTo(id))
+                                .and(PatrolTaskRecordDynamicSqlSupport.completed, isTrue())
+                        , "completed")
+                .on(PatrolTaskRecordDynamicSqlSupport.taskId.qualifiedWith("completed"), equalTo(PatrolTaskRecordDynamicSqlSupport.taskId))
+                .leftJoin(
+                        // 任务中房间总数
+                        SqlBuilder.select(PatrolTaskRecordDynamicSqlSupport.taskId, countDistinct(PatrolTaskRecordDynamicSqlSupport.roomId).as("total"))
+                                .from(PatrolTaskRecordDynamicSqlSupport.patrolTaskRecord)
+                                .where(PatrolTaskRecordDynamicSqlSupport.taskId, isEqualTo(id))
+                                .groupBy(PatrolTaskRecordDynamicSqlSupport.taskId)
+                        , "room_total")
+                .on(PatrolTaskRecordDynamicSqlSupport.taskId, equalTo(PatrolTaskRecordDynamicSqlSupport.taskId.qualifiedWith("room_total")))
+                .leftJoin(
+                        // 任务中不合格的房间数
+                        SqlBuilder.select(PatrolTaskRecordDynamicSqlSupport.roomId)
+                                .from(PatrolTaskRecordDynamicSqlSupport.patrolTaskRecord)
+                                .where(PatrolTaskRecordDynamicSqlSupport.taskId, isEqualTo(id))
+                                .and(PatrolTaskRecordDynamicSqlSupport.completed, isTrue())
+                                .and(PatrolTaskRecordDynamicSqlSupport.qualified, isFalse())
+                                .groupBy(PatrolTaskRecordDynamicSqlSupport.roomId)
+                        , "qualified"
+                ).on(PatrolTaskRecordDynamicSqlSupport.roomId.qualifiedWith("qualified"), equalTo(PatrolTaskRecordDynamicSqlSupport.roomId))
+                .where(PatrolTaskDynamicSqlSupport.id, isEqualTo(id))
+                .groupBy(PatrolTaskDynamicSqlSupport.id, PatrolTaskRecordDynamicSqlSupport.roomId, PatrolTaskRecordDynamicSqlSupport.roomName, PatrolTaskRecordDynamicSqlSupport.roomNumber, PatrolTaskRecordDynamicSqlSupport.completed, DerivedColumn.of("completed_count"))
+                .build().render(RenderingStrategies.MYBATIS3);
+        return selectRateByUserTaskRoomId(statementProvider);
+    }
+
+    @SelectProvider(type = SqlProviderAdapter.class, method = "select")
+    Optional<PatrolDetailsVO> selectDetailsByUserTaskRoomId(SelectStatementProvider selectStatement);
+
+    /**
+     * 巡检任务记录
+     */
+    default Optional<PatrolDetailsVO> selectDetailsByUserTaskRoomId(Long taskId, Long roomId) {
+        SelectStatementProvider statementProvider = SqlBuilder.select(
+                        PatrolTaskRecordDynamicSqlSupport.roomName,
+                        PatrolTaskRecordDynamicSqlSupport.roomNumber,
+                        PatrolTaskRecordDynamicSqlSupport.buildingName,
+                        PatrolTaskRecordDynamicSqlSupport.floorName,
+                        PatrolTaskDynamicSqlSupport.name,
+                        PatrolTaskDynamicSqlSupport.status,
+                        PatrolTaskDynamicSqlSupport.beginTime.as("time"),
+                        PatrolTaskRecordDynamicSqlSupport.username,
+                        sum(PatrolTaskRecordDynamicSqlSupport.score).as("score"))
+                .from(PatrolTaskDynamicSqlSupport.patrolTask)
+                .leftJoin(PatrolTaskRecordDynamicSqlSupport.patrolTaskRecord).on(PatrolTaskRecordDynamicSqlSupport.taskId, equalTo(PatrolTaskDynamicSqlSupport.id))
+                .where(PatrolTaskRecordDynamicSqlSupport.oneself, isTrue())
+                .and(PatrolTaskRecordDynamicSqlSupport.roomId, isEqualTo(roomId))
+                .and(PatrolTaskDynamicSqlSupport.id, isEqualTo(taskId))
+                .groupBy(PatrolTaskRecordDynamicSqlSupport.roomName,
+                        PatrolTaskRecordDynamicSqlSupport.roomNumber,
+                        PatrolTaskRecordDynamicSqlSupport.buildingName,
+                        PatrolTaskRecordDynamicSqlSupport.floorName,
+                        PatrolTaskDynamicSqlSupport.name,
+                        PatrolTaskDynamicSqlSupport.status,
+                        PatrolTaskDynamicSqlSupport.beginTime,
+                        PatrolTaskRecordDynamicSqlSupport.username)
+                .build().render(RenderingStrategies.MYBATIS3);
+        return selectDetailsByUserTaskRoomId(statementProvider);
+    }
+
+    @SelectProvider(type = SqlProviderAdapter.class, method = "select")
+    List<PatrolRoomRecordVO> selectRoomRecordListByPlanRoomId(SelectStatementProvider selectStatement);
+
+    /**
+     * 查询巡检任务
+     */
+    default List<PatrolRoomRecordVO> selectRoomRecordListByPlanRoomId(Long planId, Long roomId, Long userId) {
+        SelectStatementProvider statementProvider = SqlBuilder.select(
+                        PatrolTaskDynamicSqlSupport.id,
+                        PatrolTaskDynamicSqlSupport.beginTime.as("time"),
+                        PatrolTaskRecordDynamicSqlSupport.roomId,
+                        PatrolTaskRecordDynamicSqlSupport.roomName,
+                        PatrolTaskRecordDynamicSqlSupport.username,
+                        If.of(PatrolTaskRecordDynamicSqlSupport.taskId.qualifiedWith("qualified"), ">", Constant.of("0"), 0, 1).as("qualified"))
+                .from(PatrolTaskDynamicSqlSupport.patrolTask, "pt")
+                .join(PatrolTaskRecordDynamicSqlSupport.patrolTaskRecord, "ptr").on(PatrolTaskRecordDynamicSqlSupport.taskId, equalTo(PatrolTaskDynamicSqlSupport.id))
+                .leftJoin(
+                        // 任务中不合格的房间
+                        SqlBuilder.select(PatrolTaskRecordDynamicSqlSupport.taskId)
+                                .from(PatrolTaskRecordDynamicSqlSupport.patrolTaskRecord)
+                                .where(PatrolTaskRecordDynamicSqlSupport.roomId, isEqualTo(roomId))
+                                .and(PatrolTaskRecordDynamicSqlSupport.userId, isEqualTo(userId))
+                                .and(PatrolTaskRecordDynamicSqlSupport.completed, isTrue())
+                                .and(PatrolTaskRecordDynamicSqlSupport.qualified, isFalse())
+                                .groupBy(PatrolTaskRecordDynamicSqlSupport.taskId)
+                        , "qualified"
+                ).on(PatrolTaskRecordDynamicSqlSupport.taskId.qualifiedWith("qualified"), equalTo(PatrolTaskRecordDynamicSqlSupport.taskId))
+                .where(PatrolTaskDynamicSqlSupport.planId, isEqualTo(planId))
+                .and(PatrolTaskRecordDynamicSqlSupport.roomId, isEqualTo(roomId))
+                .and(PatrolTaskRecordDynamicSqlSupport.userId, isEqualTo(userId))
+                .and(PatrolTaskRecordDynamicSqlSupport.completed, isTrue())
+                .groupBy(PatrolTaskDynamicSqlSupport.id, PatrolTaskRecordDynamicSqlSupport.roomId, PatrolTaskRecordDynamicSqlSupport.roomName, PatrolTaskRecordDynamicSqlSupport.username)
+                .orderBy(PatrolTaskDynamicSqlSupport.beginTime.descending())
+                .build().render(RenderingStrategies.MYBATIS3);
+        return selectRoomRecordListByPlanRoomId(statementProvider);
+    }
+
+    @SelectProvider(type = SqlProviderAdapter.class, method = "select")
+    List<PatrolRecordVO> selectRecordList(SelectStatementProvider selectStatement);
+
+    default List<PatrolRecordVO> selectRecordList(Boolean qualified, String keyword, LocalDateTime completedTimeStart, LocalDateTime completedTimeEnd) {
+        SelectStatementProvider statementProvider;
+        if (Objects.isNull(qualified) || !qualified) {
+            statementProvider = SqlBuilder.select(
+                            PatrolTaskDynamicSqlSupport.id,
+                            PatrolTaskDynamicSqlSupport.name,
+                            PatrolTaskRecordDynamicSqlSupport.updateTime.qualifiedWith("ptr").as("time"),
+                            PatrolTaskRecordDynamicSqlSupport.roomId.qualifiedWith("ptr"),
+                            PatrolTaskRecordDynamicSqlSupport.roomName.qualifiedWith("ptr"),
+                            PatrolTaskRecordDynamicSqlSupport.username.qualifiedWith("ptr"))
+                    .from(PatrolTaskDynamicSqlSupport.patrolTask)
+                    .join(
+                            SqlBuilder.select(PatrolTaskRecordDynamicSqlSupport.taskId, PatrolTaskRecordDynamicSqlSupport.roomId, PatrolTaskRecordDynamicSqlSupport.roomName, PatrolTaskRecordDynamicSqlSupport.username, PatrolTaskRecordDynamicSqlSupport.updateTime)
+                                    .from(PatrolTaskRecordDynamicSqlSupport.patrolTaskRecord)
+                                    .where(PatrolTaskRecordDynamicSqlSupport.qualified, isEqualTo(qualified).filter(SqlExtBuilder.isNonEmpty()))
+                                    .and(PatrolTaskRecordDynamicSqlSupport.completed, isTrue())
+                                    .and(PatrolTaskRecordDynamicSqlSupport.oneself, isTrue())
+                                    .and(PatrolTaskRecordDynamicSqlSupport.updateTime, isGreaterThanOrEqualTo(completedTimeStart).filter(SqlExtBuilder.isNonEmpty()))
+                                    .and(PatrolTaskRecordDynamicSqlSupport.updateTime, isLessThanOrEqualTo(completedTimeEnd).filter(SqlExtBuilder.isNonEmpty()))
+                                    .groupBy(PatrolTaskRecordDynamicSqlSupport.taskId, PatrolTaskRecordDynamicSqlSupport.roomId, PatrolTaskRecordDynamicSqlSupport.roomName, PatrolTaskRecordDynamicSqlSupport.username, PatrolTaskRecordDynamicSqlSupport.updateTime)
+                            , "ptr")
+                    .on(PatrolTaskRecordDynamicSqlSupport.taskId.qualifiedWith("ptr"), equalTo(PatrolTaskDynamicSqlSupport.id))
+                    .where(PatrolTaskRecordDynamicSqlSupport.username.qualifiedWith("ptr"), isLikeAll(keyword).filter(SqlExtBuilder.isNonEmpty()),
+                            or(PatrolTaskDynamicSqlSupport.name, isLikeAll(keyword).filter(SqlExtBuilder.isNonEmpty())),
+                            or(PatrolTaskRecordDynamicSqlSupport.roomName.qualifiedWith("ptr"), isLikeAll(keyword).filter(SqlExtBuilder.isNonEmpty())))
+                    .build().render(RenderingStrategies.MYBATIS3);
+        } else {
+            statementProvider = SqlBuilder.select(
+                            PatrolTaskDynamicSqlSupport.id,
+                            PatrolTaskDynamicSqlSupport.name,
+                            PatrolTaskRecordDynamicSqlSupport.updateTime.qualifiedWith("ptr").as("time"),
+                            PatrolTaskRecordDynamicSqlSupport.roomId.qualifiedWith("ptr"),
+                            PatrolTaskRecordDynamicSqlSupport.roomName.qualifiedWith("ptr"),
+                            PatrolTaskRecordDynamicSqlSupport.username.qualifiedWith("ptr"))
+                    .from(PatrolTaskDynamicSqlSupport.patrolTask)
+                    .join(
+                            SqlBuilder.select(PatrolTaskRecordDynamicSqlSupport.taskId, PatrolTaskRecordDynamicSqlSupport.roomId, PatrolTaskRecordDynamicSqlSupport.roomName, PatrolTaskRecordDynamicSqlSupport.userId, PatrolTaskRecordDynamicSqlSupport.username, PatrolTaskRecordDynamicSqlSupport.updateTime,
+                                            countDistinct(PatrolTaskRecordDynamicSqlSupport.id).as("total"))
+                                    .from(PatrolTaskRecordDynamicSqlSupport.patrolTaskRecord)
+                                    .where(PatrolTaskRecordDynamicSqlSupport.completed, isTrue())
+                                    .and(PatrolTaskRecordDynamicSqlSupport.oneself, isTrue())
+                                    .and(PatrolTaskRecordDynamicSqlSupport.updateTime, isGreaterThanOrEqualTo(completedTimeStart).filter(SqlExtBuilder.isNonEmpty()))
+                                    .and(PatrolTaskRecordDynamicSqlSupport.updateTime, isLessThanOrEqualTo(completedTimeEnd).filter(SqlExtBuilder.isNonEmpty()))
+                                    .groupBy(PatrolTaskRecordDynamicSqlSupport.taskId, PatrolTaskRecordDynamicSqlSupport.roomId, PatrolTaskRecordDynamicSqlSupport.roomName, PatrolTaskRecordDynamicSqlSupport.userId, PatrolTaskRecordDynamicSqlSupport.username, PatrolTaskRecordDynamicSqlSupport.updateTime)
+                            , "ptr")
+                    .on(PatrolTaskRecordDynamicSqlSupport.taskId.qualifiedWith("ptr"), equalTo(PatrolTaskDynamicSqlSupport.id))
+                    .join(
+                            // 合格项目数
+                            SqlBuilder.select(PatrolTaskRecordDynamicSqlSupport.taskId, PatrolTaskRecordDynamicSqlSupport.roomId, PatrolTaskRecordDynamicSqlSupport.userId,
+                                            countDistinct(PatrolTaskRecordDynamicSqlSupport.id).as("qualified_total"))
+                                    .from(PatrolTaskRecordDynamicSqlSupport.patrolTaskRecord)
+                                    .where(PatrolTaskRecordDynamicSqlSupport.qualified, isTrue())
+                                    .and(PatrolTaskRecordDynamicSqlSupport.completed, isTrue())
+                                    .and(PatrolTaskRecordDynamicSqlSupport.oneself, isTrue())
+                                    .groupBy(PatrolTaskRecordDynamicSqlSupport.taskId, PatrolTaskRecordDynamicSqlSupport.roomId, PatrolTaskRecordDynamicSqlSupport.userId)
+                            , "qualified"
+                    ).on(PatrolTaskRecordDynamicSqlSupport.taskId.qualifiedWith("qualified"), equalTo(PatrolTaskRecordDynamicSqlSupport.taskId.qualifiedWith("ptr")))
+                    .and(PatrolTaskRecordDynamicSqlSupport.roomId.qualifiedWith("qualified"), equalTo(PatrolTaskRecordDynamicSqlSupport.roomId.qualifiedWith("ptr")))
+                    .and(PatrolTaskRecordDynamicSqlSupport.userId.qualifiedWith("qualified"), equalTo(PatrolTaskRecordDynamicSqlSupport.userId.qualifiedWith("ptr")))
+                    .and(DerivedColumn.of("qualified_total"), equalTo(DerivedColumn.of("total")))
+                    .where(PatrolTaskRecordDynamicSqlSupport.username.qualifiedWith("ptr"), isLikeAll(keyword).filter(SqlExtBuilder.isNonEmpty()),
+                            or(PatrolTaskDynamicSqlSupport.name, isLikeAll(keyword).filter(SqlExtBuilder.isNonEmpty())),
+                            or(PatrolTaskRecordDynamicSqlSupport.roomName.qualifiedWith("ptr"), isLikeAll(keyword).filter(SqlExtBuilder.isNonEmpty())))
+                    .build().render(RenderingStrategies.MYBATIS3);
+        }
+        return selectRecordList(statementProvider);
+    }
+
+    default List<PatrolRecordVO> selectRecordList(Boolean qualified, String keyword, LocalDateTime beginTimeStart, LocalDateTime beginTimeEnd, Integer page, Integer size) {
+        SelectStatementProvider statementProvider;
+        if (Objects.isNull(qualified) || !qualified) {
+            statementProvider = SqlBuilder.select(
+                            PatrolTaskDynamicSqlSupport.id.qualifiedWith("pt"),
+                            PatrolTaskDynamicSqlSupport.name.qualifiedWith("pt"),
+                            PatrolTaskDynamicSqlSupport.beginTime.qualifiedWith("pt").as("time"),
+                            PatrolTaskRecordDynamicSqlSupport.roomId.qualifiedWith("ptr"),
+                            PatrolTaskRecordDynamicSqlSupport.roomName.qualifiedWith("ptr"),
+                            PatrolTaskRecordDynamicSqlSupport.username.qualifiedWith("ptr"))
+                    .from(
+                            SqlBuilder.select(PatrolTaskDynamicSqlSupport.id, PatrolTaskDynamicSqlSupport.name, PatrolTaskDynamicSqlSupport.beginTime)
+                                    .from(PatrolTaskDynamicSqlSupport.patrolTask)
+                                    .where(PatrolTaskDynamicSqlSupport.beginTime, isGreaterThanOrEqualTo(beginTimeStart).filter(SqlExtBuilder.isNonEmpty()))
+                                    .and(PatrolTaskDynamicSqlSupport.beginTime, isLessThanOrEqualTo(beginTimeEnd).filter(SqlExtBuilder.isNonEmpty()))
+                                    .and(PatrolTaskDynamicSqlSupport.status, isEqualTo(TASK_STATE_COMPLETED),
+                                            or(PatrolTaskDynamicSqlSupport.status, isEqualTo(TASK_STATE_OMISSION)),
+                                            or(PatrolTaskDynamicSqlSupport.status, isEqualTo(TASK_STATE_TIMEOUT_COMPLETED)))
+                            , "pt")
+                    .join(
+                            SqlBuilder.select(PatrolTaskRecordDynamicSqlSupport.taskId, PatrolTaskRecordDynamicSqlSupport.roomId, PatrolTaskRecordDynamicSqlSupport.roomName, PatrolTaskRecordDynamicSqlSupport.username)
+                                    .from(PatrolTaskRecordDynamicSqlSupport.patrolTaskRecord)
+                                    .where(PatrolTaskRecordDynamicSqlSupport.qualified, isEqualTo(qualified).filter(SqlExtBuilder.isNonEmpty()))
+                                    .groupBy(PatrolTaskRecordDynamicSqlSupport.taskId, PatrolTaskRecordDynamicSqlSupport.roomId, PatrolTaskRecordDynamicSqlSupport.roomName, PatrolTaskRecordDynamicSqlSupport.username)
+                            , "ptr")
+                    .on(PatrolTaskRecordDynamicSqlSupport.taskId.qualifiedWith("ptr"), equalTo(PatrolTaskDynamicSqlSupport.id.qualifiedWith("pt")))
+                    .where(PatrolTaskRecordDynamicSqlSupport.username.qualifiedWith("ptr"), isLikeAll(keyword).filter(SqlExtBuilder.isNonEmpty()),
+                            or(PatrolTaskDynamicSqlSupport.name.qualifiedWith("pt"), isLikeAll(keyword).filter(SqlExtBuilder.isNonEmpty())),
+                            or(PatrolTaskRecordDynamicSqlSupport.roomName.qualifiedWith("ptr"), isLikeAll(keyword).filter(SqlExtBuilder.isNonEmpty())))
+                    .orderBy(PatrolTaskDynamicSqlSupport.beginTime.descending())
+                    .limit(size).offset((long) (page - 1) * size)
+                    .build().render(RenderingStrategies.MYBATIS3);
+        } else {
+            statementProvider = SqlBuilder.select(
+                            PatrolTaskDynamicSqlSupport.id.qualifiedWith("pt"),
+                            PatrolTaskDynamicSqlSupport.name.qualifiedWith("pt"),
+                            PatrolTaskDynamicSqlSupport.beginTime.qualifiedWith("pt").as("time"),
+                            PatrolTaskRecordDynamicSqlSupport.roomId.qualifiedWith("ptr"),
+                            PatrolTaskRecordDynamicSqlSupport.roomName.qualifiedWith("ptr"),
+                            PatrolTaskRecordDynamicSqlSupport.username.qualifiedWith("ptr"))
+                    .from(
+                            SqlBuilder.select(PatrolTaskDynamicSqlSupport.id, PatrolTaskDynamicSqlSupport.name, PatrolTaskDynamicSqlSupport.beginTime)
+                                    .from(PatrolTaskDynamicSqlSupport.patrolTask)
+                                    .where(PatrolTaskDynamicSqlSupport.beginTime, isGreaterThanOrEqualTo(beginTimeStart).filter(SqlExtBuilder.isNonEmpty()))
+                                    .and(PatrolTaskDynamicSqlSupport.beginTime, isLessThanOrEqualTo(beginTimeEnd).filter(SqlExtBuilder.isNonEmpty()))
+                                    .and(PatrolTaskDynamicSqlSupport.status, isEqualTo(TASK_STATE_COMPLETED),
+                                            or(PatrolTaskDynamicSqlSupport.status, isEqualTo(TASK_STATE_OMISSION)),
+                                            or(PatrolTaskDynamicSqlSupport.status, isEqualTo(TASK_STATE_TIMEOUT_COMPLETED)))
+                            , "pt")
+                    .join(
+                            SqlBuilder.select(PatrolTaskRecordDynamicSqlSupport.taskId, PatrolTaskRecordDynamicSqlSupport.roomId, PatrolTaskRecordDynamicSqlSupport.roomName, PatrolTaskRecordDynamicSqlSupport.userId, PatrolTaskRecordDynamicSqlSupport.username,
+                                            countDistinct(PatrolTaskRecordDynamicSqlSupport.id).as("total"))
+                                    .from(PatrolTaskRecordDynamicSqlSupport.patrolTaskRecord)
+                                    .groupBy(PatrolTaskRecordDynamicSqlSupport.taskId, PatrolTaskRecordDynamicSqlSupport.roomId, PatrolTaskRecordDynamicSqlSupport.roomName, PatrolTaskRecordDynamicSqlSupport.userId, PatrolTaskRecordDynamicSqlSupport.username)
+                            , "ptr")
+                    .on(PatrolTaskRecordDynamicSqlSupport.taskId.qualifiedWith("ptr"), equalTo(PatrolTaskDynamicSqlSupport.id.qualifiedWith("pt")))
+                    .join(
+                            // 合格项目数
+                            SqlBuilder.select(PatrolTaskRecordDynamicSqlSupport.taskId, PatrolTaskRecordDynamicSqlSupport.roomId, PatrolTaskRecordDynamicSqlSupport.userId,
+                                            countDistinct(PatrolTaskRecordDynamicSqlSupport.id).as("qualified_total"))
+                                    .from(PatrolTaskRecordDynamicSqlSupport.patrolTaskRecord)
+                                    .where(PatrolTaskRecordDynamicSqlSupport.qualified, isTrue())
+                                    .groupBy(PatrolTaskRecordDynamicSqlSupport.taskId, PatrolTaskRecordDynamicSqlSupport.roomId, PatrolTaskRecordDynamicSqlSupport.userId)
+                            , "qualified"
+                    ).on(PatrolTaskRecordDynamicSqlSupport.taskId.qualifiedWith("qualified"), equalTo(PatrolTaskRecordDynamicSqlSupport.taskId.qualifiedWith("ptr")))
+                    .and(PatrolTaskRecordDynamicSqlSupport.roomId.qualifiedWith("qualified"), equalTo(PatrolTaskRecordDynamicSqlSupport.roomId.qualifiedWith("ptr")))
+                    .and(PatrolTaskRecordDynamicSqlSupport.userId.qualifiedWith("qualified"), equalTo(PatrolTaskRecordDynamicSqlSupport.userId.qualifiedWith("ptr")))
+                    .and(DerivedColumn.of("qualified_total"), equalTo(DerivedColumn.of("total")))
+                    .where(PatrolTaskRecordDynamicSqlSupport.username.qualifiedWith("ptr"), isLikeAll(keyword).filter(SqlExtBuilder.isNonEmpty()),
+                            or(PatrolTaskDynamicSqlSupport.name.qualifiedWith("pt"), isLikeAll(keyword).filter(SqlExtBuilder.isNonEmpty())),
+                            or(PatrolTaskRecordDynamicSqlSupport.roomName.qualifiedWith("ptr"), isLikeAll(keyword).filter(SqlExtBuilder.isNonEmpty())))
+                    .orderBy(PatrolTaskDynamicSqlSupport.beginTime.descending())
+                    .limit(size).offset((long) (page - 1) * size)
+                    .build().render(RenderingStrategies.MYBATIS3);
+        }
+        return selectRecordList(statementProvider);
+    }
+}

+ 111 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/patrol/PatrolTaskRecordExtMapper.java

@@ -0,0 +1,111 @@
+package com.chuanghai.patrol.service.mapper.patrol;
+
+import com.chuanghai.patrol.dao.PatrolTaskRecordDynamicSqlSupport;
+import com.chuanghai.patrol.dao.PatrolTaskRecordMapper;
+import com.chuanghai.patrol.vo.PatrolCheckItemVO;
+import com.chuanghai.patrol.vo.PatrolDeviceVO;
+import com.chuanghai.patrol.vo.PatrolRoomCheckItemVO;
+import com.chuanghai.patrol.vo.PatrolRoomDeviceVO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.ResultMap;
+import org.apache.ibatis.annotations.SelectProvider;
+import org.mybatis.dynamic.sql.SqlBuilder;
+import org.mybatis.dynamic.sql.render.RenderingStrategies;
+import org.mybatis.dynamic.sql.select.render.SelectStatementProvider;
+import org.mybatis.dynamic.sql.util.SqlProviderAdapter;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+import java.util.List;
+
+import static org.mybatis.dynamic.sql.SqlBuilder.*;
+
+@Mapper
+public interface PatrolTaskRecordExtMapper extends PatrolTaskRecordMapper, CommonSelectMapper {
+
+    @SelectProvider(type = SqlProviderAdapter.class, method = "select")
+    List<PatrolRoomCheckItemVO> selectCheckItemListByUserTaskRoomId(SelectStatementProvider selectStatement);
+
+    /**
+     * 巡检房间关联的检查项记录
+     */
+    default List<PatrolRoomCheckItemVO> selectCheckItemListByUserTaskRoomId(Long userId, Long taskId, Long roomId) {
+        SelectStatementProvider statementProvider = SqlBuilder.select(
+                        PatrolTaskRecordDynamicSqlSupport.id,
+                        PatrolTaskRecordDynamicSqlSupport.checkItemSnapshot.as("check_item"))
+                .from(PatrolTaskRecordDynamicSqlSupport.patrolTaskRecord)
+                .where(PatrolTaskRecordDynamicSqlSupport.userId, isEqualTo(userId))
+                .and(PatrolTaskRecordDynamicSqlSupport.taskId, isEqualTo(taskId))
+                .and(PatrolTaskRecordDynamicSqlSupport.roomId, isEqualTo(roomId))
+                .and(PatrolTaskRecordDynamicSqlSupport.deviceId, isNull())
+                .build().render(RenderingStrategies.MYBATIS3);
+        return selectCheckItemListByUserTaskRoomId(statementProvider);
+    }
+
+    @ResultMap("taskDevice")
+    @SelectProvider(type = SqlProviderAdapter.class, method = "select")
+    List<PatrolRoomDeviceVO> selectDeviceListByUserTaskRoomId(SelectStatementProvider selectStatement);
+
+    /**
+     * 巡检设备关联的检查项记录
+     */
+    default List<PatrolRoomDeviceVO> selectDeviceListByUserTaskRoomId(Long userId, Long taskId, Long roomId) {
+        SelectStatementProvider statementProvider = SqlBuilder.select(
+                        PatrolTaskRecordDynamicSqlSupport.id,
+                        PatrolTaskRecordDynamicSqlSupport.deviceName,
+                        PatrolTaskRecordDynamicSqlSupport.deviceId,
+                        PatrolTaskRecordDynamicSqlSupport.checkItemSnapshot.as("check_item"))
+                .from(PatrolTaskRecordDynamicSqlSupport.patrolTaskRecord)
+                .where(PatrolTaskRecordDynamicSqlSupport.userId, isEqualTo(userId))
+                .and(PatrolTaskRecordDynamicSqlSupport.taskId, isEqualTo(taskId))
+                .and(PatrolTaskRecordDynamicSqlSupport.roomId, isEqualTo(roomId))
+                .and(PatrolTaskRecordDynamicSqlSupport.deviceId, isNotNull())
+                .build().render(RenderingStrategies.MYBATIS3);
+        return selectDeviceListByUserTaskRoomId(statementProvider);
+    }
+
+    @SelectProvider(type = SqlProviderAdapter.class, method = "select")
+    List<PatrolCheckItemVO> selectRecordCheckItemListByUserTaskRoomId(SelectStatementProvider selectStatement);
+
+    /**
+     * 巡检房间关联的检查项记录
+     */
+    default List<PatrolCheckItemVO> selectRecordCheckItemListByUserTaskRoomId(Long taskId, Long roomId) {
+        SelectStatementProvider statementProvider = SqlBuilder.select(
+                        PatrolTaskRecordDynamicSqlSupport.checkItemType,
+                        PatrolTaskRecordDynamicSqlSupport.checkItemName,
+                        PatrolTaskRecordDynamicSqlSupport.checkItemSnapshot.as("check_item"),
+                        PatrolTaskRecordDynamicSqlSupport.value)
+                .from(PatrolTaskRecordDynamicSqlSupport.patrolTaskRecord)
+                .where(PatrolTaskRecordDynamicSqlSupport.oneself, isTrue())
+                .and(PatrolTaskRecordDynamicSqlSupport.taskId, isEqualTo(taskId))
+                .and(PatrolTaskRecordDynamicSqlSupport.roomId, isEqualTo(roomId))
+                .and(PatrolTaskRecordDynamicSqlSupport.deviceId, isNull())
+                .build().render(RenderingStrategies.MYBATIS3);
+        return selectRecordCheckItemListByUserTaskRoomId(statementProvider);
+    }
+
+    @ResultMap("taskRecordDevice")
+    @SelectProvider(type = SqlProviderAdapter.class, method = "select")
+    List<PatrolDeviceVO> selectRecordDeviceListByUserTaskRoomId(SelectStatementProvider selectStatement);
+
+    /**
+     * 巡检设备关联的检查项记录
+     */
+    default List<PatrolDeviceVO> selectRecordDeviceListByUserTaskRoomId(Long taskId, Long roomId) {
+        SelectStatementProvider statementProvider = SqlBuilder.select(
+                        PatrolTaskRecordDynamicSqlSupport.id,
+                        PatrolTaskRecordDynamicSqlSupport.deviceId,
+                        PatrolTaskRecordDynamicSqlSupport.deviceName,
+                        PatrolTaskRecordDynamicSqlSupport.checkItemType,
+                        PatrolTaskRecordDynamicSqlSupport.checkItemName,
+                        PatrolTaskRecordDynamicSqlSupport.checkItemSnapshot.as("check_item"),
+                        PatrolTaskRecordDynamicSqlSupport.value)
+                .from(PatrolTaskRecordDynamicSqlSupport.patrolTaskRecord)
+                .where(PatrolTaskRecordDynamicSqlSupport.oneself, isTrue())
+                .and(PatrolTaskRecordDynamicSqlSupport.taskId, isEqualTo(taskId))
+                .and(PatrolTaskRecordDynamicSqlSupport.roomId, isEqualTo(roomId))
+                .and(PatrolTaskRecordDynamicSqlSupport.deviceId, isNotNull())
+                .build().render(RenderingStrategies.MYBATIS3);
+        return selectRecordDeviceListByUserTaskRoomId(statementProvider);
+    }
+}

+ 9 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/stock/StockChangeRecordExtMapper.java

@@ -0,0 +1,9 @@
+package com.chuanghai.patrol.service.mapper.stock;
+
+import com.chuanghai.patrol.dao.StockChangeRecordMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+@Mapper
+public interface StockChangeRecordExtMapper extends StockChangeRecordMapper, CommonSelectMapper {
+}

+ 9 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/stock/StockClassifyExtMapper.java

@@ -0,0 +1,9 @@
+package com.chuanghai.patrol.service.mapper.stock;
+
+import com.chuanghai.patrol.dao.StockClassifyMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+@Mapper
+public interface StockClassifyExtMapper extends StockClassifyMapper, CommonSelectMapper {
+}

+ 9 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/stock/StockGoodsExtMapper.java

@@ -0,0 +1,9 @@
+package com.chuanghai.patrol.service.mapper.stock;
+
+import com.chuanghai.patrol.dao.StockGoodsMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+@Mapper
+public interface StockGoodsExtMapper extends StockGoodsMapper, CommonSelectMapper {
+}

+ 9 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/system/SystemAttendanceExtMapper.java

@@ -0,0 +1,9 @@
+package com.chuanghai.patrol.service.mapper.system;
+
+import com.chuanghai.patrol.dao.SystemAttendanceMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+@Mapper
+public interface SystemAttendanceExtMapper extends SystemAttendanceMapper, CommonSelectMapper {
+}

+ 9 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/system/SystemDatabaseBackupExtMapper.java

@@ -0,0 +1,9 @@
+package com.chuanghai.patrol.service.mapper.system;
+
+import com.chuanghai.patrol.dao.SystemDatabaseBackupMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+@Mapper
+public interface SystemDatabaseBackupExtMapper extends SystemDatabaseBackupMapper, CommonSelectMapper {
+}

+ 9 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/system/SystemDeptExtMapper.java

@@ -0,0 +1,9 @@
+package com.chuanghai.patrol.service.mapper.system;
+
+import com.chuanghai.patrol.dao.SystemDeptMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+@Mapper
+public interface SystemDeptExtMapper extends SystemDeptMapper, CommonSelectMapper {
+}

+ 9 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/system/SystemElectricityExtMapper.java

@@ -0,0 +1,9 @@
+package com.chuanghai.patrol.service.mapper.system;
+
+import com.chuanghai.patrol.dao.SystemElectricityMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+@Mapper
+public interface SystemElectricityExtMapper extends SystemElectricityMapper, CommonSelectMapper {
+}

+ 9 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/system/SystemLogExtMapper.java

@@ -0,0 +1,9 @@
+package com.chuanghai.patrol.service.mapper.system;
+
+import com.chuanghai.patrol.dao.SystemLogMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+@Mapper
+public interface SystemLogExtMapper extends SystemLogMapper, CommonSelectMapper {
+}

+ 9 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/system/SystemLoginLogExtMapper.java

@@ -0,0 +1,9 @@
+package com.chuanghai.patrol.service.mapper.system;
+
+import com.chuanghai.patrol.dao.SystemLoginLogMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+@Mapper
+public interface SystemLoginLogExtMapper extends SystemLoginLogMapper, CommonSelectMapper {
+}

+ 9 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/system/SystemPermissionsExtMapper.java

@@ -0,0 +1,9 @@
+package com.chuanghai.patrol.service.mapper.system;
+
+import com.chuanghai.patrol.dao.SystemPermissionsMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+@Mapper
+public interface SystemPermissionsExtMapper extends SystemPermissionsMapper, CommonSelectMapper {
+}

+ 9 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/system/SystemRoleExtMapper.java

@@ -0,0 +1,9 @@
+package com.chuanghai.patrol.service.mapper.system;
+
+import com.chuanghai.patrol.dao.SystemRoleMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+@Mapper
+public interface SystemRoleExtMapper extends SystemRoleMapper, CommonSelectMapper {
+}

+ 9 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/system/SystemUserCommentExtMapper.java

@@ -0,0 +1,9 @@
+package com.chuanghai.patrol.service.mapper.system;
+
+import com.chuanghai.patrol.dao.SystemUserCommentMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+@Mapper
+public interface SystemUserCommentExtMapper extends SystemUserCommentMapper, CommonSelectMapper {
+}

+ 69 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/system/SystemUserExtMapper.java

@@ -0,0 +1,69 @@
+package com.chuanghai.patrol.service.mapper.system;
+
+import com.chuanghai.patrol.dao.SystemDeptDynamicSqlSupport;
+import com.chuanghai.patrol.dao.SystemUserDynamicSqlSupport;
+import com.chuanghai.patrol.dao.SystemUserMapper;
+import com.chuanghai.patrol.vo.OptionVO;
+import com.chuanghai.patrol.vo.SystemDeptUserVO;
+import com.flyhigh.core.mybatis.SqlExtBuilder;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.ResultMap;
+import org.apache.ibatis.annotations.SelectProvider;
+import org.mybatis.dynamic.sql.SqlBuilder;
+import org.mybatis.dynamic.sql.render.RenderingStrategies;
+import org.mybatis.dynamic.sql.select.render.SelectStatementProvider;
+import org.mybatis.dynamic.sql.util.SqlProviderAdapter;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+import java.util.List;
+
+import static com.chuanghai.patrol.config.AppConstant.SUPPER_ADMIN_ID;
+import static com.flyhigh.core.mybatis.SqlExtBuilder.isLikeAll;
+import static org.mybatis.dynamic.sql.SqlBuilder.*;
+
+@Mapper
+public interface SystemUserExtMapper extends SystemUserMapper, CommonSelectMapper {
+
+    @SelectProvider(type = SqlProviderAdapter.class, method = "select")
+    List<OptionVO> selectUserOptionListByKeyword(SelectStatementProvider selectStatement);
+
+    /**
+     * 用户选项
+     */
+    default List<OptionVO> selectUserOptionListByKeyword(String keyword) {
+        SelectStatementProvider selectStatement = SqlBuilder.select(SystemUserDynamicSqlSupport.id, SystemUserDynamicSqlSupport.username.as("name"))
+                .from(SystemUserDynamicSqlSupport.systemUser)
+                .where(SystemUserDynamicSqlSupport.disabled, isFalse())
+                .and(SystemUserDynamicSqlSupport.id, isNotEqualTo(SUPPER_ADMIN_ID))
+                .and(SystemUserDynamicSqlSupport.username, isLikeAll(keyword).filter(SqlExtBuilder.isNonEmpty()), or(SystemUserDynamicSqlSupport.telephone, isLikeAll(keyword).filter(SqlExtBuilder.isNonEmpty())))
+                .orderBy(SystemUserDynamicSqlSupport.username, SystemUserDynamicSqlSupport.telephone)
+                .build().render(RenderingStrategies.MYBATIS3);
+        return selectUserOptionListByKeyword(selectStatement);
+    }
+
+    @ResultMap("deptUser")
+    @SelectProvider(type = SqlProviderAdapter.class, method = "select")
+    List<SystemDeptUserVO> selectDeptUserByUsername(SelectStatementProvider selectStatement);
+
+    /**
+     * 部门用户
+     */
+    default List<SystemDeptUserVO> selectDeptUserByUsername(String username) {
+        SelectStatementProvider selectStatement = SqlBuilder.select(
+                        SystemDeptDynamicSqlSupport.id,
+                        SystemDeptDynamicSqlSupport.name,
+                        SystemUserDynamicSqlSupport.id.as("user_id"),
+                        SystemUserDynamicSqlSupport.username,
+                        SystemUserDynamicSqlSupport.telephone)
+                .from(SystemDeptDynamicSqlSupport.systemDept)
+                .leftJoin(SystemUserDynamicSqlSupport.systemUser).on(SystemUserDynamicSqlSupport.deptId, equalTo(SystemDeptDynamicSqlSupport.id))
+                .where(SystemUserDynamicSqlSupport.username, isLikeAll(username).filter(SqlExtBuilder.isNonEmpty()))
+                .and(SystemUserDynamicSqlSupport.disabled, isFalse())
+                .and(SystemUserDynamicSqlSupport.id, isNotEqualTo(SUPPER_ADMIN_ID))
+                .groupBy(SystemDeptDynamicSqlSupport.id,
+                        SystemUserDynamicSqlSupport.id)
+                .orderBy(SystemUserDynamicSqlSupport.username)
+                .build().render(RenderingStrategies.MYBATIS3);
+        return selectDeptUserByUsername(selectStatement);
+    }
+}

+ 9 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/temporarytask/TemporaryTaskAndSystemUserExtMapper.java

@@ -0,0 +1,9 @@
+package com.chuanghai.patrol.service.mapper.temporarytask;
+
+import com.chuanghai.patrol.dao.TemporaryTaskAndSystemUserMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+@Mapper
+public interface TemporaryTaskAndSystemUserExtMapper extends TemporaryTaskAndSystemUserMapper, CommonSelectMapper {
+}

+ 153 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/temporarytask/TemporaryTaskExtMapper.java

@@ -0,0 +1,153 @@
+package com.chuanghai.patrol.service.mapper.temporarytask;
+
+import com.chuanghai.patrol.dao.*;
+import com.chuanghai.patrol.vo.TemporaryTaskStatusVO;
+import com.chuanghai.patrol.vo.TemporaryTaskVO;
+import com.flyhigh.core.mybatis.SqlExtBuilder;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.ResultMap;
+import org.apache.ibatis.annotations.SelectProvider;
+import org.mybatis.dynamic.sql.SqlBuilder;
+import org.mybatis.dynamic.sql.render.RenderingStrategies;
+import org.mybatis.dynamic.sql.select.render.SelectStatementProvider;
+import org.mybatis.dynamic.sql.util.SqlProviderAdapter;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+import static com.flyhigh.core.mybatis.SqlExtBuilder.isLikeAll;
+import static org.mybatis.dynamic.sql.SqlBuilder.*;
+
+@Mapper
+public interface TemporaryTaskExtMapper extends TemporaryTaskMapper, CommonSelectMapper {
+
+    /**
+     * 查询临时任务id列表
+     */
+    default List<Long> selectTaskIds(String title, Integer type, Integer status, Integer auditStatus, String content, String username, String executor, LocalDateTime startTime, LocalDateTime endTime) {
+        SelectStatementProvider selectStatement = SqlBuilder.selectDistinct(
+                        TemporaryTaskDynamicSqlSupport.id,
+                        TemporaryTaskDynamicSqlSupport.title,
+                        TemporaryTaskDynamicSqlSupport.type,
+                        TemporaryTaskDynamicSqlSupport.status,
+                        TemporaryTaskDynamicSqlSupport.auditStatus,
+                        TemporaryTaskDynamicSqlSupport.publishTime,
+                        TemporaryTaskDynamicSqlSupport.finishTime,
+                        TemporaryTaskDynamicSqlSupport.feedbackTotal,
+                        SystemUserDynamicSqlSupport.username
+                )
+                .from(TemporaryTaskDynamicSqlSupport.temporaryTask)
+                .leftJoin(SystemUserDynamicSqlSupport.systemUser).on(SystemUserDynamicSqlSupport.id, equalTo(TemporaryTaskDynamicSqlSupport.userId))
+                .leftJoin(TemporaryTaskAndSystemUserDynamicSqlSupport.temporaryTaskAndSystemUser).on(TemporaryTaskAndSystemUserDynamicSqlSupport.taskId, equalTo(TemporaryTaskDynamicSqlSupport.id))
+                .leftJoin(SystemUserDynamicSqlSupport.systemUser.withAlias("executor")).on(SystemUserDynamicSqlSupport.id.qualifiedWith("executor"), equalTo(TemporaryTaskAndSystemUserDynamicSqlSupport.userId))
+                .where(TemporaryTaskDynamicSqlSupport.title, isLikeAll(title).filter(SqlExtBuilder.isNonEmpty()))
+                .and(TemporaryTaskDynamicSqlSupport.type, isEqualTo(type).filter(SqlExtBuilder.isNonEmpty()))
+                .and(TemporaryTaskDynamicSqlSupport.status, isEqualTo(status).filter(SqlExtBuilder.isNonEmpty()))
+                .and(TemporaryTaskDynamicSqlSupport.auditStatus, isEqualTo(auditStatus).filter(SqlExtBuilder.isNonEmpty()))
+                .and(TemporaryTaskDynamicSqlSupport.content, isLikeAll(content).filter(SqlExtBuilder.isNonEmpty()))
+                .and(SystemUserDynamicSqlSupport.username, isLikeAll(username).filter(SqlExtBuilder.isNonEmpty()))
+                .and(TemporaryTaskDynamicSqlSupport.publishTime, isGreaterThanOrEqualTo(startTime).filter(SqlExtBuilder.isNonEmpty()))
+                .and(TemporaryTaskDynamicSqlSupport.publishTime, isLessThanOrEqualTo(endTime).filter(SqlExtBuilder.isNonEmpty()))
+                .and(SystemUserDynamicSqlSupport.username.qualifiedWith("executor"), isLikeAll(executor).filter(SqlExtBuilder.isNonEmpty()))
+                .build().render(RenderingStrategies.MYBATIS3);
+        return selectManyLongs(selectStatement);
+    }
+
+    @ResultMap("task")
+    @SelectProvider(type = SqlProviderAdapter.class, method = "select")
+    List<TemporaryTaskVO> selectListByTaskIds(SelectStatementProvider selectStatement);
+
+    /**
+     * 查询临时任务
+     */
+    default List<TemporaryTaskVO> selectListByTaskIds(List<Long> taskIds, String order) {
+        SelectStatementProvider selectStatement = SqlBuilder.select(TemporaryTaskDynamicSqlSupport.temporaryTask.allColumns(),
+                        DeviceRoomDynamicSqlSupport.name.as("roomName"), SystemUserDynamicSqlSupport.username, SystemUserDynamicSqlSupport.username.qualifiedWith("executor").as("executor"))
+                .from(TemporaryTaskDynamicSqlSupport.temporaryTask)
+                .leftJoin(SystemUserDynamicSqlSupport.systemUser).on(SystemUserDynamicSqlSupport.id, equalTo(TemporaryTaskDynamicSqlSupport.userId))
+                .leftJoin(DeviceRoomDynamicSqlSupport.deviceRoom).on(DeviceRoomDynamicSqlSupport.id, equalTo(TemporaryTaskDynamicSqlSupport.roomId))
+                .leftJoin(TemporaryTaskAndSystemUserDynamicSqlSupport.temporaryTaskAndSystemUser).on(TemporaryTaskAndSystemUserDynamicSqlSupport.taskId, equalTo(TemporaryTaskDynamicSqlSupport.id))
+                .leftJoin(SystemUserDynamicSqlSupport.systemUser.withAlias("executor")).on(SystemUserDynamicSqlSupport.id.qualifiedWith("executor"), equalTo(TemporaryTaskAndSystemUserDynamicSqlSupport.userId))
+                .where(TemporaryTaskDynamicSqlSupport.id, isIn(taskIds))
+                .orderBy(SqlBuilder.sortColumn(order))
+                .build().render(RenderingStrategies.MYBATIS3);
+        return selectListByTaskIds(selectStatement);
+    }
+
+    @SelectProvider(type = SqlProviderAdapter.class, method = "select")
+    List<TemporaryTaskStatusVO> selectStatisticalListByUserId(SelectStatementProvider selectStatement);
+
+    /**
+     * 我收到的临时任务统计
+     */
+    default List<TemporaryTaskStatusVO> selectReceiveStatisticalListByUserId(long userId) {
+        SelectStatementProvider selectStatement = SqlBuilder.select(TemporaryTaskDynamicSqlSupport.status, SqlBuilder.count(TemporaryTaskDynamicSqlSupport.id).as("count"))
+                .from(TemporaryTaskDynamicSqlSupport.temporaryTask)
+                .leftJoin(TemporaryTaskAndSystemUserDynamicSqlSupport.temporaryTaskAndSystemUser).on(TemporaryTaskAndSystemUserDynamicSqlSupport.taskId, equalTo(TemporaryTaskDynamicSqlSupport.id))
+                .where(TemporaryTaskAndSystemUserDynamicSqlSupport.userId, isEqualTo(userId))
+                .groupBy(TemporaryTaskDynamicSqlSupport.status)
+                .build().render(RenderingStrategies.MYBATIS3);
+        return selectStatisticalListByUserId(selectStatement);
+    }
+
+    /**
+     * 我发出的临时任务统计
+     */
+    default List<TemporaryTaskStatusVO> selectPublishStatisticalListByUserId(long userId) {
+        SelectStatementProvider selectStatement = SqlBuilder.select(TemporaryTaskDynamicSqlSupport.status, SqlBuilder.count(TemporaryTaskDynamicSqlSupport.id).as("count"))
+                .from(TemporaryTaskDynamicSqlSupport.temporaryTask)
+                .where(TemporaryTaskDynamicSqlSupport.userId, isEqualTo(userId))
+                .groupBy(TemporaryTaskDynamicSqlSupport.status)
+                .build().render(RenderingStrategies.MYBATIS3);
+        return selectStatisticalListByUserId(selectStatement);
+    }
+
+    /**
+     * 根据执行人查询临时任务id列表
+     */
+    default List<Long> selectTaskIdsByExecutor(Integer status, Long executor) {
+        SelectStatementProvider selectStatement = SqlBuilder.selectDistinct(TemporaryTaskDynamicSqlSupport.id)
+                .from(TemporaryTaskDynamicSqlSupport.temporaryTask)
+                .leftJoin(TemporaryTaskAndSystemUserDynamicSqlSupport.temporaryTaskAndSystemUser).on(TemporaryTaskAndSystemUserDynamicSqlSupport.taskId, equalTo(TemporaryTaskDynamicSqlSupport.id))
+                .where(TemporaryTaskDynamicSqlSupport.status, isEqualTo(status))
+                .and(TemporaryTaskAndSystemUserDynamicSqlSupport.userId, isEqualTo(executor))
+                .build().render(RenderingStrategies.MYBATIS3);
+        return selectManyLongs(selectStatement);
+    }
+
+    /**
+     * 根据发布人查询临时任务id列表
+     */
+    default List<Long> selectTaskIdsByPublisher(Integer status, Long publisher) {
+        SelectStatementProvider selectStatement = SqlBuilder.selectDistinct(TemporaryTaskDynamicSqlSupport.id)
+                .from(TemporaryTaskDynamicSqlSupport.temporaryTask)
+                .where(TemporaryTaskDynamicSqlSupport.status, isEqualTo(status))
+                .and(TemporaryTaskDynamicSqlSupport.userId, isEqualTo(publisher))
+                .build().render(RenderingStrategies.MYBATIS3);
+        return selectManyLongs(selectStatement);
+    }
+
+    @ResultMap("task")
+    @SelectProvider(type = SqlProviderAdapter.class, method = "select")
+    TemporaryTaskVO selectNewestByExecutor(SelectStatementProvider selectStatement);
+
+    /**
+     * 根据执行人查询最新一条临时任务
+     */
+    default TemporaryTaskVO selectNewestByExecutor(Long executor, Integer status) {
+        SelectStatementProvider selectStatement = SqlBuilder.select(TemporaryTaskDynamicSqlSupport.temporaryTask.allColumns(),
+                        DeviceRoomDynamicSqlSupport.name.as("roomName"), SystemUserDynamicSqlSupport.username, SystemUserDynamicSqlSupport.username.qualifiedWith("executor").as("executor"))
+                .from(TemporaryTaskDynamicSqlSupport.temporaryTask)
+                .leftJoin(DeviceRoomDynamicSqlSupport.deviceRoom).on(DeviceRoomDynamicSqlSupport.id, equalTo(TemporaryTaskDynamicSqlSupport.roomId))
+                .leftJoin(SystemUserDynamicSqlSupport.systemUser).on(SystemUserDynamicSqlSupport.id, equalTo(TemporaryTaskDynamicSqlSupport.userId))
+                .leftJoin(TemporaryTaskAndSystemUserDynamicSqlSupport.temporaryTaskAndSystemUser).on(TemporaryTaskAndSystemUserDynamicSqlSupport.taskId, equalTo(TemporaryTaskDynamicSqlSupport.id))
+                .leftJoin(SystemUserDynamicSqlSupport.systemUser.withAlias("executor")).on(SystemUserDynamicSqlSupport.id.qualifiedWith("executor"), equalTo(TemporaryTaskAndSystemUserDynamicSqlSupport.userId))
+                .where(TemporaryTaskAndSystemUserDynamicSqlSupport.userId, isEqualTo(executor))
+                .and(TemporaryTaskDynamicSqlSupport.status, isEqualToWhenPresent(status))
+                .orderBy(TemporaryTaskDynamicSqlSupport.publishTime.descending())
+                .limit(1)
+                .build().render(RenderingStrategies.MYBATIS3);
+        return selectNewestByExecutor(selectStatement);
+    }
+}

+ 9 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/temporarytask/TemporaryTaskFeedbackExtMapper.java

@@ -0,0 +1,9 @@
+package com.chuanghai.patrol.service.mapper.temporarytask;
+
+import com.chuanghai.patrol.dao.TemporaryTaskFeedbackMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+@Mapper
+public interface TemporaryTaskFeedbackExtMapper extends TemporaryTaskFeedbackMapper, CommonSelectMapper {
+}

+ 9 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/upkeep/UpkeepPlanExtMapper.java

@@ -0,0 +1,9 @@
+package com.chuanghai.patrol.service.mapper.upkeep;
+
+import com.chuanghai.patrol.dao.UpkeepPlanMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+@Mapper
+public interface UpkeepPlanExtMapper extends UpkeepPlanMapper, CommonSelectMapper {
+}

+ 9 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/upkeep/UpkeepTaskExtMapper.java

@@ -0,0 +1,9 @@
+package com.chuanghai.patrol.service.mapper.upkeep;
+
+import com.chuanghai.patrol.dao.UpkeepTaskMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+@Mapper
+public interface UpkeepTaskExtMapper extends UpkeepTaskMapper, CommonSelectMapper {
+}

+ 9 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/visitor/VisitorAuditExtMapper.java

@@ -0,0 +1,9 @@
+package com.chuanghai.patrol.service.mapper.visitor;
+
+import com.chuanghai.patrol.dao.VisitorAuditMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+@Mapper
+public interface VisitorAuditExtMapper extends VisitorAuditMapper, CommonSelectMapper {
+}

+ 9 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/visitor/VisitorBackupExtMapper.java

@@ -0,0 +1,9 @@
+package com.chuanghai.patrol.service.mapper.visitor;
+
+import com.chuanghai.patrol.dao.VisitorBackupMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+@Mapper
+public interface VisitorBackupExtMapper extends VisitorBackupMapper, CommonSelectMapper {
+}

+ 9 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/mapper/visitor/VisitorRegulationExtMapper.java

@@ -0,0 +1,9 @@
+package com.chuanghai.patrol.service.mapper.visitor;
+
+import com.chuanghai.patrol.dao.VisitorRegulationMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper;
+
+@Mapper
+public interface VisitorRegulationExtMapper extends VisitorRegulationMapper, CommonSelectMapper {
+}

+ 448 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/patrol/PatrolTaskExtService.java

@@ -0,0 +1,448 @@
+package com.chuanghai.patrol.service.patrol;
+
+import com.chuanghai.patrol.config.AppConstant;
+import com.chuanghai.patrol.dao.PatrolTaskRecordDynamicSqlSupport;
+import com.chuanghai.patrol.dao.SystemAttendanceDynamicSqlSupport;
+import com.chuanghai.patrol.entity.PageInfo;
+import com.chuanghai.patrol.from.PatrolTaskRecordItemFrom;
+import com.chuanghai.patrol.from.PatrolTaskRecordUpdateFrom;
+import com.chuanghai.patrol.model.CheckRoute;
+import com.chuanghai.patrol.model.PatrolTask;
+import com.chuanghai.patrol.model.PatrolTaskRecord;
+import com.chuanghai.patrol.model.SystemAttendance;
+import com.chuanghai.patrol.service.mapper.checkitem.CheckItemExtMapper;
+import com.chuanghai.patrol.service.mapper.checkroute.CheckRouteExtMapper;
+import com.chuanghai.patrol.service.mapper.device.DeviceExtMapper;
+import com.chuanghai.patrol.service.mapper.device.DeviceRoomExtMapper;
+import com.chuanghai.patrol.service.mapper.patrol.PatrolTaskExtMapper;
+import com.chuanghai.patrol.service.mapper.patrol.PatrolTaskRecordExtMapper;
+import com.chuanghai.patrol.service.mapper.system.SystemAttendanceExtMapper;
+import com.chuanghai.patrol.vo.*;
+import com.flyhigh.core.ApplicationContext;
+import com.flyhigh.core.exception.CustomizeException;
+import com.flyhigh.core.util.DateUtil;
+import com.flyhigh.core.util.JsonUtil;
+import com.flyhigh.core.util.RedisUtil;
+import com.flyhigh.core.util.SQLUtil;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageSerializable;
+import lombok.RequiredArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.Pair;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import static com.chuanghai.patrol.config.AppConstant.*;
+import static org.mybatis.dynamic.sql.SqlBuilder.*;
+
+/**
+ * 巡检任务服务
+ */
+@Service
+@RequiredArgsConstructor
+public class PatrolTaskExtService extends ApplicationContext {
+    private final PatrolTaskExtMapper patrolTaskExtMapper;
+    private final PatrolTaskRecordExtMapper patrolTaskRecordExtMapper;
+    private final SystemAttendanceExtMapper systemAttendanceExtMapper;
+    private final DeviceRoomExtMapper deviceRoomExtMapper;
+    private final CheckRouteExtMapper checkRouteExtMapper;
+    private final CheckItemExtMapper checkItemExtMapper;
+    private final DeviceExtMapper deviceExtMapper;
+
+    /**
+     * 巡检任务
+     */
+    public PageInfo<PatrolTaskVO> selectList(LocalDateTime beginTimeStart, LocalDateTime beginTimeEnd, Integer page, Integer size) {
+        PageSerializable<Long> pageSerializable = PageHelper.startPage(page, size).doSelectPageSerializable(() -> patrolTaskExtMapper.selectTaskIdList(beginTimeStart, beginTimeEnd));
+        if (pageSerializable.getList().isEmpty()) {
+            return new PageInfo<>(pageSerializable.getTotal(), new ArrayList<>());
+        }
+        List<PatrolTaskVO> patrolTaskVOList = patrolTaskExtMapper.selectList(pageSerializable.getList());
+        return PageInfo.of(pageSerializable.getTotal(), patrolTaskVOList);
+    }
+
+    /**
+     * 巡检任务
+     */
+    public List<PatrolTaskVO> selectListByRoom(Long roomId) {
+        // 任务状态为已开始,任务中的房间有未巡检项
+        List<Long> ids = patrolTaskExtMapper.selectTaskIdListByRoomId(curUserId(), roomId);
+        if (ids.isEmpty()) {
+            return new ArrayList<>();
+        }
+        return patrolTaskExtMapper.selectTaskListByIds(curUserId(), ids);
+    }
+
+    /**
+     * 巡检进度
+     */
+    public PatrolRateVO queryRate(Long id) {
+        return patrolTaskExtMapper.selectRateByUserTaskRoomId(id).orElseThrow(() -> CustomizeException.exceptionClient("sys_data_does_not_exist"));
+    }
+
+    /**
+     * 巡检详情
+     */
+    public PatrolDetailsVO queryRecord(Long taskId, Long roomId) {
+        PatrolDetailsVO patrolDetailsVO = patrolTaskExtMapper.selectDetailsByUserTaskRoomId(taskId, roomId).orElseThrow(() -> CustomizeException.exceptionClient("sys_data_does_not_exist"));
+        patrolDetailsVO.setQualified(patrolTaskRecordExtMapper.count(c -> c.where(PatrolTaskRecordDynamicSqlSupport.taskId, isEqualTo(taskId))
+                .and(PatrolTaskRecordDynamicSqlSupport.roomId, isEqualTo(roomId))
+                .and(PatrolTaskRecordDynamicSqlSupport.oneself, isTrue())
+                .and(PatrolTaskRecordDynamicSqlSupport.completed, isTrue())
+                .and(PatrolTaskRecordDynamicSqlSupport.qualified, isFalse())) == 0);
+        patrolDetailsVO.setCheckItems(patrolTaskRecordExtMapper.selectRecordCheckItemListByUserTaskRoomId(taskId, roomId));
+        patrolDetailsVO.setDevices(patrolTaskRecordExtMapper.selectRecordDeviceListByUserTaskRoomId(taskId, roomId));
+        return patrolDetailsVO;
+    }
+
+    /**
+     * 巡检任务
+     */
+    public PatrolRoomDetailsVO query(Long taskId, Long roomId) {
+        PatrolRoomDetailsVO patrolRoomDetailsVO = patrolTaskExtMapper.selectByUserTaskRoomId(curUserId(), taskId, roomId).orElseThrow(() -> CustomizeException.exceptionClient("sys_data_does_not_exist"));
+        patrolRoomDetailsVO.setCheckItems(patrolTaskRecordExtMapper.selectCheckItemListByUserTaskRoomId(curUserId(), taskId, roomId));
+        patrolRoomDetailsVO.setDevices(patrolTaskRecordExtMapper.selectDeviceListByUserTaskRoomId(curUserId(), taskId, roomId));
+        return patrolRoomDetailsVO;
+    }
+
+    /**
+     * 未开始任务房间详情
+     */
+    public DeviceRoomDetailsVO queryRoomDetails(Long taskId, Long roomId) {
+        DeviceRoomDetailsVO deviceRoomDetailsVO = deviceRoomExtMapper.selectById(roomId).orElseThrow(() -> CustomizeException.exceptionClient("房间不存在"));
+        PatrolTask patrolTask = patrolTaskExtMapper.selectByPrimaryKey(taskId).orElseThrow(() -> CustomizeException.exceptionClient("任务不存在"));
+        CheckRoute checkRoute = checkRouteExtMapper.selectByPrimaryKey(patrolTask.getRouteId()).orElseThrow(() -> CustomizeException.exceptionClient("路线不存在"));
+        deviceRoomDetailsVO.setRouteName(checkRoute.getName());
+        deviceRoomDetailsVO.setCheckItems(checkItemExtMapper.selectOptionListByRoomAndRoute(roomId));
+        deviceRoomDetailsVO.setDevices(deviceExtMapper.selectListByRoomAndRoute(roomId));
+        return deviceRoomDetailsVO;
+    }
+
+    /**
+     * 更新巡检任务记录
+     */
+    public Boolean update(PatrolTaskRecordUpdateFrom patrolTaskRecordUpdateFrom) {
+        PatrolTask patrolTask = patrolTaskExtMapper.selectByPrimaryKey(patrolTaskRecordUpdateFrom.getTaskId()).orElseThrow(() -> CustomizeException.exceptionClient("任务不存在"));
+        // 任务已开始后可提交
+        if (patrolTask.getStatus() == AppConstant.TASK_STATE_NOT_STARTED) {
+            throw CustomizeException.exceptionClient("任务未开始");
+        }
+        // 任务已完成
+        if (patrolTask.getStatus() == TASK_STATE_COMPLETED || patrolTask.getStatus() == TASK_STATE_TIMEOUT_COMPLETED) {
+            throw CustomizeException.exceptionClient("任务已完成");
+        }
+        if (patrolTask.getDisabled()) {
+            throw CustomizeException.exceptionClient("任务已关闭");
+        }
+        // 当前用户、房间下所有未完成的检查项
+        List<PatrolTaskRecord> patrolTaskRecords = patrolTaskRecordExtMapper.select(c -> c.where(PatrolTaskRecordDynamicSqlSupport.taskId, isEqualTo(patrolTask.getId())).
+                and(PatrolTaskRecordDynamicSqlSupport.roomId, isEqualTo(patrolTaskRecordUpdateFrom.getRoomId()))
+                .and(PatrolTaskRecordDynamicSqlSupport.userId, isEqualTo(curUserId()))
+                .and(PatrolTaskRecordDynamicSqlSupport.completed, isFalse()));
+        if (patrolTaskRecords.isEmpty()) {
+            throw CustomizeException.exceptionClient("当前房间无检查项或所有检查项都已完成");
+        }
+        Map<Long, PatrolTaskRecordItemFrom> recordItemFromMap = patrolTaskRecordUpdateFrom.getItems().stream().collect(Collectors.toMap(PatrolTaskRecordItemFrom::getId, Function.identity(), (v1, v2) -> {
+            throw CustomizeException.exceptionClient("检查记录重复");
+        }));
+        String cacheKey;
+        //防重复提交
+        if (patrolTask.getRunModel() == RUN_MODEL_ONE) {
+            // 任务-房间不能重复提交
+            cacheKey = String.format("%s_task_%d_%d", getCoreProperties().getApplicationName(), patrolTaskRecordUpdateFrom.getTaskId(), patrolTaskRecordUpdateFrom.getRoomId());
+            if (RedisUtil.hasKey(cacheKey)) {
+                throw CustomizeException.exceptionClient("其他人正在提交,请10s后再试");
+            }
+        } else {
+            // 任务-房间-用户不能重复提交
+            cacheKey = String.format("%s_task_%d_%d_%d", getCoreProperties().getApplicationName(), patrolTaskRecordUpdateFrom.getTaskId(), patrolTaskRecordUpdateFrom.getRoomId(), curUserId());
+            if (RedisUtil.hasKey(cacheKey)) {
+                throw CustomizeException.exceptionClient("请勿重复提交");
+            }
+        }
+        RedisUtil.set(cacheKey, "任务提交", 10, TimeUnit.SECONDS);
+        LocalDateTime now = DateUtil.now();
+        // 其他用户所有完成的检查项
+        List<PatrolTaskRecord> otherUserPatrolTaskRecords = new ArrayList<>();
+        if (patrolTask.getRunModel() == RUN_MODEL_ONE) {
+            otherUserPatrolTaskRecords = patrolTaskRecordExtMapper.select(c -> c.where(PatrolTaskRecordDynamicSqlSupport.taskId, isEqualTo(patrolTask.getId())).
+                    and(PatrolTaskRecordDynamicSqlSupport.roomId, isEqualTo(patrolTaskRecordUpdateFrom.getRoomId()))
+                    .and(PatrolTaskRecordDynamicSqlSupport.userId, isNotEqualTo(curUserId()))
+                    .and(PatrolTaskRecordDynamicSqlSupport.completed, isFalse()));
+        }
+        for (PatrolTaskRecord patrolTaskRecord : patrolTaskRecords) {
+            PatrolTaskRecordItemFrom patrolTaskRecordItemFrom = recordItemFromMap.get(patrolTaskRecord.getId());
+            if (Objects.isNull(patrolTaskRecordItemFrom)) {
+                RedisUtil.delete(cacheKey);
+                throw CustomizeException.exceptionClient(patrolTaskRecord.getCheckItemName() + " 未提交");
+            }
+            // 计算得分
+            Pair<Integer, Boolean> result = Pair.of(0, true);
+            try {
+                if (patrolTaskRecord.getCheckItemType() == AppConstant.CHECK_ITEM_TYPE_SELECT) {
+                    result = getSelectScore(patrolTaskRecordItemFrom, patrolTaskRecord.getCheckItemSnapshot());
+                } else if (patrolTaskRecord.getCheckItemType() == AppConstant.CHECK_ITEM_TYPE_NUM) {
+                    result = getNumScore(patrolTaskRecordItemFrom, patrolTaskRecord.getCheckItemSnapshot());
+                } else if (patrolTaskRecord.getCheckItemType() == AppConstant.CHECK_ITEM_TYPE_TXT) {
+                    result = getTxtScore(patrolTaskRecordItemFrom, patrolTaskRecord.getCheckItemSnapshot());
+                } else if (patrolTaskRecord.getCheckItemType() == AppConstant.CHECK_ITEM_TYPE_PHOTO) {
+                    result = getPhotoScore(patrolTaskRecordItemFrom, patrolTaskRecord.getCheckItemSnapshot());
+                }
+            } catch (CustomizeException exception) {
+                RedisUtil.delete(cacheKey);
+                throw exception;
+            }
+            patrolTaskRecord.setCompleted(true).setScore(result.getLeft()).setQualified(result.getRight()).setOneself(true).setValue(patrolTaskRecordItemFrom.getValue()).setUpdateTime(now);
+            patrolTaskRecordExtMapper.updateByPrimaryKeySelective(patrolTaskRecord);
+            // 执行模式为其中一人时为其他人完成任务
+            if (patrolTask.getRunModel() == RUN_MODEL_ONE && !otherUserPatrolTaskRecords.isEmpty()) {
+                int finalScore = result.getLeft();
+                boolean finalQualified = result.getRight();
+                otherUserPatrolTaskRecords.stream().filter(p -> p.getTaskId().equals(patrolTaskRecord.getTaskId())
+                                && p.getCheckItemId().equals(patrolTaskRecord.getCheckItemId()))
+                        .forEach(p -> {
+                                    p.setCompleted(true).setScore(finalScore).setQualified(finalQualified).setOneself(false).setValue(patrolTaskRecordItemFrom.getValue()).setUpdateTime(now);
+                                    patrolTaskRecordExtMapper.updateByPrimaryKeySelective(p);
+                                }
+                        );
+            }
+        }
+        // 考勤得分
+        Set<Long> users = new HashSet<>();
+        users.add(curUserId());
+        // 执行模式为其中一人时为其他人添加得分
+        if (patrolTask.getRunModel() == RUN_MODEL_ONE && !otherUserPatrolTaskRecords.isEmpty()) {
+            users.addAll(otherUserPatrolTaskRecords.stream().map(PatrolTaskRecord::getUserId).distinct().collect(Collectors.toList()));
+        }
+        //月份
+        String month = patrolTask.getBeginTime().format(DateTimeFormatter.ofPattern("yyyy-MM"));
+        List<SystemAttendance> systemAttendances = new ArrayList<>();
+        for (Long user : users) {
+            // 未完成项目数
+            long size = patrolTaskRecordExtMapper.count(c -> c.where(
+                            PatrolTaskRecordDynamicSqlSupport.taskId, isEqualTo(patrolTask.getId()))
+                    .and(PatrolTaskRecordDynamicSqlSupport.userId, isEqualTo(user))
+                    .and(PatrolTaskRecordDynamicSqlSupport.completed, isFalse())
+            );
+
+            // 超时完成
+            if (size == 0 && patrolTask.getEndTime().isBefore(now)) {
+                // 超时任务已减5分,超时完成后加回3分
+                int score = 3;
+                //上次得分
+                Optional<SystemAttendance> systemAttendanceOptional = systemAttendanceExtMapper.selectOne(c ->
+                        c.where(SystemAttendanceDynamicSqlSupport.userId, isEqualTo(user))
+                                .and(SystemAttendanceDynamicSqlSupport.month, isEqualTo(month))
+                                .orderBy(SystemAttendanceDynamicSqlSupport.id.descending())
+                                .limit(1)
+                );
+                if (systemAttendanceOptional.isPresent()) {
+                    SystemAttendance lastSystemAttendance = systemAttendanceOptional.get();
+                    SystemAttendance systemAttendance = SystemAttendance.builder()
+                            .userId(user)
+                            .lastScore(lastSystemAttendance.getCurrentScore())
+                            .changeScore(score)
+                            .currentScore(lastSystemAttendance.getCurrentScore() + score)
+                            .month(month)
+                            .type(ATTENDANCE_TASK)
+                            .event("任务[" + patrolTask.getName() + "]超时完成得分")
+                            .createTime(now)
+                            .build();
+                    systemAttendances.add(systemAttendance);
+                }
+            }
+        }
+        if (!systemAttendances.isEmpty()) {
+            systemAttendanceExtMapper.insertMultiple(systemAttendances);
+        }
+
+        // 任务未完成项目数
+        long size = patrolTaskRecordExtMapper.count(c -> c.where(
+                        PatrolTaskRecordDynamicSqlSupport.taskId, isEqualTo(patrolTask.getId()))
+                .and(PatrolTaskRecordDynamicSqlSupport.completed, isFalse())
+        );
+        if (size == 0) {
+            // 超时
+            if (patrolTask.getEndTime().isBefore(now)) {
+                patrolTask.setStatus(TASK_STATE_TIMEOUT_COMPLETED);
+            } else {
+                patrolTask.setStatus(TASK_STATE_COMPLETED);
+            }
+            patrolTaskExtMapper.updateByPrimaryKey(patrolTask);
+        }
+        return Boolean.TRUE;
+    }
+
+    /**
+     * 巡检记录
+     */
+    public PageInfo<PatrolRoomRecordVO> selectRoomRecordList(Long taskId, Long roomId, Integer page, Integer size) {
+        PatrolTask patrolTask = patrolTaskExtMapper.selectByPrimaryKey(taskId).orElseThrow(() -> CustomizeException.exceptionClient("sys_data_does_not_exist"));
+        PageSerializable<PatrolRoomRecordVO> pageSerializable = PageHelper.startPage(page, size).doSelectPageSerializable(() -> patrolTaskExtMapper.selectRoomRecordListByPlanRoomId(patrolTask.getPlanId(), roomId, curUserId()));
+        return PageInfo.of(pageSerializable);
+    }
+
+    /**
+     * 巡检记录
+     */
+    public PageInfo<PatrolRecordVO> selectRecordList(Boolean qualified, String keyword, LocalDateTime completedTimeStart, LocalDateTime completedTimeEnd, Integer page, Integer size, String order) {
+        order = SQLUtil.orderConvert(order);
+        PageSerializable<PatrolRecordVO> pageSerializable = PageHelper.startPage(page, size).setOrderBy(order).doSelectPageSerializable(() -> patrolTaskExtMapper.selectRecordList(qualified, keyword, completedTimeStart, completedTimeEnd));
+        return PageInfo.of(pageSerializable);
+    }
+
+    /**
+     * 巡检记录
+     */
+    public PageInfo<PatrolRecordVO> selectRecordList(Boolean qualified, String keyword, LocalDateTime beginTimeStart, LocalDateTime beginTimeEnd, Integer page, Integer size) {
+        List<PatrolRecordVO> list = patrolTaskExtMapper.selectRecordList(qualified, keyword, beginTimeStart, beginTimeEnd, page, size);
+        return PageInfo.of(0, list);
+    }
+
+    /**
+     * 选择计算得分
+     */
+    private Pair<Integer, Boolean> getSelectScore(PatrolTaskRecordItemFrom item, String checkItemSnapshot) {
+        // 记录值
+        final Set<Long> value = new HashSet<>();
+        if (StringUtils.isNoneBlank(item.getValue())) {
+            value.addAll(Arrays.stream(item.getValue().split(",")).map(Long::valueOf).collect(Collectors.toSet()));
+        }
+        CheckItemSelectDetailsVO checkItem = JsonUtil.parseObject(checkItemSnapshot, CheckItemSelectDetailsVO.class);
+        // 单选
+        if (!checkItem.getAllowMultiple() && value.size() > 1) {
+            throw CustomizeException.exceptionClient(checkItem.getCheckItem().getItemName() + " 不能多选");
+        }
+        // 必填时记录值不可空
+        if (checkItem.getCheckItem().getIsRequired()) {
+            if (value.isEmpty() || value.contains(0L)) {
+                throw CustomizeException.exceptionClient(checkItem.getCheckItem().getItemName() + " 是必填项");
+            }
+        }
+        AtomicInteger score = new AtomicInteger(0);
+        AtomicBoolean qualified = new AtomicBoolean(true);
+        // 判断是否合格
+        checkItem.getOptions().forEach(option -> {
+            if (value.contains(option.getId())) {
+                if (option.getQualifiedIfSelect()) {
+                    // 选中合格且选中
+                    score.addAndGet(option.getScore());
+                } else {
+                            qualified.set(false);
+                        }
+                    } else {
+                        if (option.getQualifiedIfNoSelect()) {
+                            // 未选中合格且未选中
+                            score.addAndGet(option.getScore());
+                        } else {
+                            qualified.set(false);
+                        }
+                    }
+                }
+        );
+        return Pair.of(score.get(), qualified.get());
+    }
+
+    /**
+     * 数字计算得分
+     */
+    private Pair<Integer, Boolean> getNumScore(PatrolTaskRecordItemFrom item, String checkItemSnapshot) {
+        CheckItemNumDetailsVO checkItem = JsonUtil.parseObject(checkItemSnapshot, CheckItemNumDetailsVO.class);
+        // 记录值
+        Float value = null;
+        if (StringUtils.isNoneBlank(item.getValue())) {
+            try {
+                value = Float.valueOf(item.getValue());
+            } catch (NumberFormatException e) {
+                throw CustomizeException.exceptionClient(checkItem.getCheckItem().getItemName() + " 数据错误");
+            }
+        }
+        int score = checkItem.getExtra().getQualifiedScore();
+        boolean qualified = true;
+        // 必填时记录值不可空
+        if (checkItem.getCheckItem().getIsRequired() && Objects.isNull(value)) {
+            throw CustomizeException.exceptionClient(checkItem.getCheckItem().getItemName() + " 是必填项");
+        }
+
+        if (checkItem.getExtra().getCheckValidMaxValue() && (Objects.isNull(value) || value > Float.parseFloat(checkItem.getExtra().getValidMaxValue()))) {
+            // 有效值上限判断
+            throw CustomizeException.exceptionClient(checkItem.getCheckItem().getItemName() + " 数值超过有效值上限");
+        }
+        if (checkItem.getExtra().getCheckValidMinValue() && (Objects.isNull(value) || value < Float.parseFloat(checkItem.getExtra().getValidMinValue()))) {
+            // 有效值下限判断
+            throw CustomizeException.exceptionClient(checkItem.getCheckItem().getItemName() + " 数值超过有效值下限");
+        }
+
+        if ((checkItem.getExtra().getCheckQualifiedMaxValue() && (Objects.isNull(value) || value > Float.parseFloat(checkItem.getExtra().getQualifiedMaxValue())))
+                || (checkItem.getExtra().getCheckQualifiedMinValue() && (Objects.isNull(value) || value < Float.parseFloat(checkItem.getExtra().getQualifiedMinValue())))) {
+            // 不合格
+            score = checkItem.getExtra().getNoQualifiedScore();
+            qualified = false;
+        }
+        return Pair.of(score, qualified);
+    }
+
+    /**
+     * 文本项计算得分
+     */
+    private Pair<Integer, Boolean> getTxtScore(PatrolTaskRecordItemFrom item, String checkItemSnapshot) {
+        // 记录值
+        String value = item.getValue();
+        CheckItemTxtDetailsVO checkItem = JsonUtil.parseObject(checkItemSnapshot, CheckItemTxtDetailsVO.class);
+        int score = checkItem.getExtra().getNoQualifiedScore();
+        boolean qualified = false;
+        // 必填时记录值不可空
+        if (checkItem.getCheckItem().getIsRequired() && StringUtils.isBlank(value)) {
+            throw CustomizeException.exceptionClient(checkItem.getCheckItem().getItemName() + " 是必填项");
+        }
+        // 始终合格 有内容合格 无内容合格
+        if (checkItem.getExtra().getQualifiedJudge() == 1 ||
+                (checkItem.getExtra().getQualifiedJudge() == 3 && StringUtils.isBlank(value)) ||
+                (checkItem.getExtra().getQualifiedJudge() == 4 && StringUtils.isNoneBlank(value))) {
+            score = checkItem.getExtra().getQualifiedScore();
+            qualified = true;
+        }
+        return Pair.of(score, qualified);
+    }
+
+    /**
+     * 拍照项计算得分
+     */
+    private Pair<Integer, Boolean> getPhotoScore(PatrolTaskRecordItemFrom item, String checkItemSnapshot) {
+        CheckItemPhotoDetailsVO checkItem = JsonUtil.parseObject(checkItemSnapshot, CheckItemPhotoDetailsVO.class);
+        // 记录值
+        Map<Long, PatrolTaskRecordItemFrom> value = JsonUtil.parseList(item.getValue(), PatrolTaskRecordItemFrom.class).orElse(new ArrayList<>())
+                .stream().collect(Collectors.toMap(PatrolTaskRecordItemFrom::getId, Function.identity()));
+        AtomicInteger score = new AtomicInteger(0);
+        AtomicBoolean qualified = new AtomicBoolean(true);
+        // 拍照项
+        checkItem.getPhotoPoints().forEach(photoPoint -> {
+                    // 必须拍照
+                    if (photoPoint.getIsRequired() && (!value.containsKey(photoPoint.getId()) || StringUtils.isBlank(value.get(photoPoint.getId()).getValue()))) {
+                        throw CustomizeException.exceptionClient("拍照点 " + photoPoint.getName() + " 必须要拍照");
+                    }
+
+                    if (photoPoint.getQualifiedJudge() && value.containsKey(photoPoint.getId()) && StringUtils.isNoneBlank(value.get(photoPoint.getId()).getValue())) {
+                        // 拍照合格且有拍照
+                        score.addAndGet(photoPoint.getQualifiedScore());
+                    } else if (!photoPoint.getQualifiedJudge() && (!value.containsKey(photoPoint.getId()) || StringUtils.isBlank(value.get(photoPoint.getId()).getValue()))) {
+                        // 不拍照合格且无拍照
+                        score.addAndGet(photoPoint.getQualifiedScore());
+                    } else {
+                        score.addAndGet(photoPoint.getNoQualifiedScore());
+                        qualified.set(false);
+                    }
+                }
+        );
+        return Pair.of(score.get(), qualified.get());
+    }
+
+}

+ 37 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/system/SystemUserCommentExtService.java

@@ -0,0 +1,37 @@
+package com.chuanghai.patrol.service.system;
+
+import com.chuanghai.patrol.config.AppConstant;
+import com.chuanghai.patrol.from.SystemUserCommentAddFrom;
+import com.chuanghai.patrol.model.SystemUserComment;
+import com.chuanghai.patrol.service.mapper.system.SystemUserCommentExtMapper;
+import com.flyhigh.core.ApplicationContext;
+import com.flyhigh.core.util.DateUtil;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+/**
+ * 用户评价服务
+ */
+@Service
+@RequiredArgsConstructor
+public class SystemUserCommentExtService extends ApplicationContext {
+    private final SystemUserCommentExtMapper systemUserCommentExtMapper;
+
+    /**
+     * 添加用户评价
+     */
+    public SystemUserComment add(SystemUserCommentAddFrom systemUserCommentAddFrom) {
+        SystemUserComment userComment = SystemUserComment.builder()
+                .userId(curUserId())
+                .username(curUserInfo(AppConstant.USERNAME))
+                .respondentUserId(systemUserCommentAddFrom.getRespondentUserId())
+                .respondentUsername(systemUserCommentAddFrom.getRespondentUsername())
+                .content(systemUserCommentAddFrom.getContent())
+                .images(systemUserCommentAddFrom.getImages())
+                .score(systemUserCommentAddFrom.getScore())
+                .createTime(DateUtil.now())
+                .build();
+        systemUserCommentExtMapper.insertSelective(userComment);
+        return userComment;
+    }
+}

+ 153 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/system/SystemUserExtService.java

@@ -0,0 +1,153 @@
+package com.chuanghai.patrol.service.system;
+
+import com.chuanghai.patrol.config.AppConstant;
+import com.chuanghai.patrol.dao.SystemUserDynamicSqlSupport;
+import com.chuanghai.patrol.entity.PageInfo;
+import com.chuanghai.patrol.from.SystemUserLoginFrom;
+import com.chuanghai.patrol.from.SystemUserPasswordUpdateFrom;
+import com.chuanghai.patrol.model.SystemLoginLog;
+import com.chuanghai.patrol.model.SystemUser;
+import com.chuanghai.patrol.service.mapper.system.SystemDeptExtMapper;
+import com.chuanghai.patrol.service.mapper.system.SystemLoginLogExtMapper;
+import com.chuanghai.patrol.service.mapper.system.SystemUserExtMapper;
+import com.chuanghai.patrol.vo.OptionVO;
+import com.chuanghai.patrol.vo.SystemDeptUserVO;
+import com.chuanghai.patrol.vo.SystemLoginVO;
+import com.flyhigh.core.ApplicationContext;
+import com.flyhigh.core.config.CoreConstant;
+import com.flyhigh.core.entity.UserCache;
+import com.flyhigh.core.exception.CustomizeException;
+import com.flyhigh.core.util.*;
+import com.github.pagehelper.PageHelper;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+import static org.mybatis.dynamic.sql.SqlBuilder.isEqualTo;
+
+/**
+ * 用户服务
+ */
+@Service
+@RequiredArgsConstructor
+public class SystemUserExtService extends ApplicationContext {
+    private final SystemUserExtMapper systemUserExtMapper;
+    private final SystemLoginLogExtMapper systemLoginLogExtMapper;
+    private final SystemDeptExtMapper systemDeptExtMapper;
+
+    /**
+     * 用户登录
+     */
+    public SystemLoginVO updateUserAuth(SystemUserLoginFrom systemUserLoginFrom) {
+        //1. 查询用户是否存在
+        SystemUser user = systemUserExtMapper.selectOne(c ->
+                c.where(SystemUserDynamicSqlSupport.username, isEqualTo(systemUserLoginFrom.getUsername()))
+                        .or(SystemUserDynamicSqlSupport.telephone, isEqualTo(systemUserLoginFrom.getUsername()))
+        ).orElseThrow(() -> CustomizeException.exceptionClient("sys_data_does_not_exist"));
+        if (user.getDisabled()) {
+            throw CustomizeException.exceptionClient("sys_data_disabled");
+        }
+        // 密码加密
+        String encryptPassword = CipherUtil.encryptAES(systemUserLoginFrom.getPassword(), getCoreProperties().getPasswordKey(), getCoreProperties().getPasswordIv());
+        System.out.println("加密后的密码:"+encryptPassword);
+        //2. 校验密码
+        if (user.getPassword().equals(encryptPassword)) {
+            //3. 生成token
+            LocalDateTime loginTime = DateUtil.now();
+            long uuid = idWorker.nextId();
+            String token = JWTUtil.createToken(claims -> {
+                claims.put(AppConstant.USER_ID, user.getId());
+                claims.put(AppConstant.USER_UUID, uuid);
+                return claims;
+            }, getCoreProperties().getTokenSecret());
+
+            // 单用户模式时删除用户id对应的权限信息
+            if (!getCoreProperties().isMultiUser()) {
+                RedisUtil.delete(RedisUtil.scan(String.format(CoreConstant.REDIS_USER_PATTERN, getCoreProperties().getApplicationName(), user.getId())));
+            }
+
+            //4. 保存用户信息到缓存
+            String key = String.format(CoreConstant.REDIS_USER, getCoreProperties().getApplicationName(), user.getId(), uuid);
+            UserCache userCache = UserCache.builder()
+                    .key(key)
+                    .createTime(DateUtil.localDateTimeToTimestamp(loginTime))
+                    .updateTime(DateUtil.localDateTimeToTimestamp(loginTime))
+                    .obtainTime(DateUtil.localDateTimeToTimestamp(loginTime))
+                    .info(new HashMap<String, String>() {
+                        {
+                            put(AppConstant.USERNAME, user.getUsername());
+                        }
+                    })
+                    .build();
+
+            //缓存 用户Id_uuid->用户权限
+            RedisUtil.set(key, userCache, getCoreProperties().getTokenExpiresTime(), TimeUnit.MILLISECONDS);
+            String deptName = null;
+            if (Objects.nonNull(user.getDeptId())) {
+                deptName = systemDeptExtMapper.selectByPrimaryKey(user.getDeptId()).orElseThrow(() -> CustomizeException.exceptionSystem("部门不存在")).getName();
+            }
+            //5. 保存登录日志
+            systemLoginLogExtMapper.insertSelective(SystemLoginLog.builder().userId(user.getId()).address(AddressUtil.getRealAddressByIP(getIp())).platform(2).loginTime(loginTime).ip(getIp()).build());
+            return SystemLoginVO.builder()
+                    .token(token)
+                    .id(user.getId())
+                    .username(user.getUsername())
+                    .telephone(user.getTelephone())
+                    .deptName(deptName)
+                    .build();
+        } else {
+            throw CustomizeException.exceptionClient("password_error");
+        }
+    }
+
+    /**
+     * 更新用户密码
+     */
+    public Boolean updatePassword(SystemUserPasswordUpdateFrom systemUserPasswordUpdateFrom) {
+        SystemUser systemUser = systemUserExtMapper.selectByPrimaryKey(curUserId()).orElseThrow(() -> CustomizeException.exceptionClient("用户不存在"));
+        String encryptPasswordOld = CipherUtil.encryptAES(systemUserPasswordUpdateFrom.getPasswordOld(), getCoreProperties().getPasswordKey(), getCoreProperties().getPasswordIv());
+        if (!systemUser.getPassword().equals(encryptPasswordOld)) {
+            throw CustomizeException.exceptionClient("原密码错误");
+        }
+        String encryptPassword = CipherUtil.encryptAES(systemUserPasswordUpdateFrom.getPassword(), getCoreProperties().getPasswordKey(), getCoreProperties().getPasswordIv());
+        systemUser.setPassword(encryptPassword);
+        int update = systemUserExtMapper.updateByPrimaryKeySelective(systemUser);
+        if (update > 0) {
+            offlineUser(curUserId());
+        }
+        return Boolean.TRUE;
+    }
+
+    /**
+     * 通过用户名或手机号查询用户选项
+     */
+    public PageInfo<OptionVO> selectOptionList(String keyword, Integer page, Integer size) {
+        return PageInfo.of(PageHelper.startPage(page, size).doSelectPageSerializable(() -> systemUserExtMapper.selectUserOptionListByKeyword(keyword)));
+    }
+
+    /**
+     * 下线用户
+     */
+    private void offlineUser(Long... userIds) {
+        // 用户id对应的所有的key
+        Arrays.stream(userIds)
+                .distinct()
+                .forEach(userId -> RedisUtil.delete(RedisUtil.scan(String.format(CoreConstant.REDIS_USER_PATTERN, getCoreProperties().getApplicationName(), userId))));
+        Arrays.stream(userIds)
+                .distinct()
+                .forEach(userId -> RedisUtil.delete(RedisUtil.scan(String.format("patrol-web_user_%d_*", userId))));
+    }
+
+    /**
+     * 部门用户
+     */
+    public List<SystemDeptUserVO> selectDeptUserList(String username) {
+        return systemUserExtMapper.selectDeptUserByUsername(username);
+    }
+}

+ 212 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/temporarytask/TemporaryTaskExtService.java

@@ -0,0 +1,212 @@
+package com.chuanghai.patrol.service.temporarytask;
+
+import com.chuanghai.patrol.dao.SystemAttendanceDynamicSqlSupport;
+import com.chuanghai.patrol.dao.TemporaryTaskAndSystemUserDynamicSqlSupport;
+import com.chuanghai.patrol.entity.PageInfo;
+import com.chuanghai.patrol.from.TemporaryTaskAddFrom;
+import com.chuanghai.patrol.from.TemporaryTaskStatusUpdateFrom;
+import com.chuanghai.patrol.model.SystemAttendance;
+import com.chuanghai.patrol.model.TemporaryTask;
+import com.chuanghai.patrol.model.TemporaryTaskAndSystemUser;
+import com.chuanghai.patrol.service.mapper.device.DeviceRoomExtMapper;
+import com.chuanghai.patrol.service.mapper.system.SystemAttendanceExtMapper;
+import com.chuanghai.patrol.service.mapper.temporarytask.TemporaryTaskAndSystemUserExtMapper;
+import com.chuanghai.patrol.service.mapper.temporarytask.TemporaryTaskExtMapper;
+import com.chuanghai.patrol.vo.TemporaryTaskStatusVO;
+import com.chuanghai.patrol.vo.TemporaryTaskVO;
+import com.flyhigh.core.ApplicationContext;
+import com.flyhigh.core.exception.CustomizeException;
+import com.flyhigh.core.util.DateUtil;
+import com.flyhigh.core.util.SQLUtil;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageSerializable;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import static com.chuanghai.patrol.config.AppConstant.*;
+import static org.mybatis.dynamic.sql.SqlBuilder.isEqualTo;
+
+/**
+ * 临时任务服务
+ */
+@Service
+@RequiredArgsConstructor
+public class TemporaryTaskExtService extends ApplicationContext {
+    private final TemporaryTaskExtMapper temporaryTaskExtMapper;
+    private final SystemAttendanceExtMapper systemAttendanceExtMapper;
+    private final TemporaryTaskAndSystemUserExtMapper temporaryTaskAndSystemUserExtMapper;
+    private final DeviceRoomExtMapper deviceRoomExtMapper;
+
+    /**
+     * 添加临时任务
+     */
+    public TemporaryTask add(TemporaryTaskAddFrom temporaryTaskAddFrom) {
+        deviceRoomExtMapper.selectByPrimaryKey(temporaryTaskAddFrom.getRoomId()).orElseThrow(() -> CustomizeException.exceptionClient("房间不存在"));
+        TemporaryTask task = TemporaryTask.builder()
+                .roomId(temporaryTaskAddFrom.getRoomId())
+                .belongSystem(temporaryTaskAddFrom.getBelongSystem())
+                .title(temporaryTaskAddFrom.getTitle())
+                .type(temporaryTaskAddFrom.getType())
+                .content(temporaryTaskAddFrom.getContent())
+                .userId(curUserId())
+                .status(TEMPORARY_TASK_STATUS_PROCESSING)
+                .auditStatus(TEMPORARY_TASK_AUDIT_STATUS_UN_SUBMITTED)
+                .publishTime(DateUtil.now())
+                .finishTime(temporaryTaskAddFrom.getFinishTime())
+                .images(temporaryTaskAddFrom.getImages())
+                .build();
+
+        temporaryTaskExtMapper.insertSelective(task);
+        List<TemporaryTaskAndSystemUser> executorAndUsers = temporaryTaskAddFrom.getExecutors().stream().map(item -> TemporaryTaskAndSystemUser.builder().taskId(task.getId()).userId(item).build()).collect(Collectors.toList());
+        temporaryTaskAndSystemUserExtMapper.insertMultiple(executorAndUsers);
+        // 发布任务得分
+        //月份
+        LocalDateTime now = DateUtil.now();
+        String month = now.format(DateTimeFormatter.ofPattern("yyyy-MM"));
+        //上次得分
+        Optional<SystemAttendance> systemAttendanceOptional = systemAttendanceExtMapper.selectOne(c ->
+                c.where(SystemAttendanceDynamicSqlSupport.userId, isEqualTo(curUserId()))
+                        .and(SystemAttendanceDynamicSqlSupport.month, isEqualTo(month))
+                        .orderBy(SystemAttendanceDynamicSqlSupport.id.descending())
+                        .limit(1)
+        );
+        if (systemAttendanceOptional.isPresent()) {
+            SystemAttendance lastSystemAttendance = systemAttendanceOptional.get();
+            SystemAttendance systemAttendance = SystemAttendance.builder()
+                    .userId(curUserId())
+                    .lastScore(lastSystemAttendance.getCurrentScore())
+                    .changeScore(1)
+                    .currentScore(lastSystemAttendance.getCurrentScore() + 1)
+                    .month(month)
+                    .type(ATTENDANCE_TASK)
+                    .event("发布临时任务[" + temporaryTaskAddFrom.getTitle() + "]得分")
+                    .createTime(now)
+                    .build();
+            systemAttendanceExtMapper.insertSelective(systemAttendance);
+        }
+        return task;
+    }
+
+    /**
+     * 更新临时任务
+     */
+    public TemporaryTask update(TemporaryTaskStatusUpdateFrom temporaryTaskStatusUpdateFrom) {
+        TemporaryTask task = temporaryTaskExtMapper.selectByPrimaryKey(temporaryTaskStatusUpdateFrom.getId()).orElseThrow(() -> CustomizeException.exceptionClient("sys_data_does_not_exist"));
+        //已完成或已取消
+        if (task.getStatus().equals(TEMPORARY_TASK_STATUS_COMPLETED) || task.getStatus().equals(TEMPORARY_TASK_STATUS_CANCELLED)) {
+            throw CustomizeException.exceptionClient("任务已完成或已取消");
+        }
+        // 1:完成 2:取消 3:不通过
+        if (temporaryTaskStatusUpdateFrom.getStatus() == 1) {
+            task.setStatus(TEMPORARY_TASK_STATUS_COMPLETED);
+        } else if (temporaryTaskStatusUpdateFrom.getStatus() == 2) {
+            task.setStatus(TEMPORARY_TASK_STATUS_CANCELLED);
+        } else if (temporaryTaskStatusUpdateFrom.getStatus() == 3) {
+            task.setAuditStatus(TEMPORARY_TASK_AUDIT_STATUS_FAIL);
+            task.setRemark(temporaryTaskStatusUpdateFrom.getRemake());
+        }
+        temporaryTaskExtMapper.updateByPrimaryKeySelective(task);
+        if (task.getStatus().equals(TEMPORARY_TASK_STATUS_COMPLETED)) {
+            // 完成临时任务得分
+            //月份
+            LocalDateTime now = DateUtil.now();
+            String month = now.format(DateTimeFormatter.ofPattern("yyyy-MM"));
+            List<SystemAttendance> systemAttendances = new ArrayList<>();
+            List<TemporaryTaskAndSystemUser> taskAndSystemUsers = temporaryTaskAndSystemUserExtMapper.select(c -> c.where(TemporaryTaskAndSystemUserDynamicSqlSupport.taskId, isEqualTo(task.getId())));
+            for (TemporaryTaskAndSystemUser user : taskAndSystemUsers) {
+                //上次得分
+                Optional<SystemAttendance> systemAttendanceOptional = systemAttendanceExtMapper.selectOne(c ->
+                        c.where(SystemAttendanceDynamicSqlSupport.userId, isEqualTo(user.getUserId()))
+                                .and(SystemAttendanceDynamicSqlSupport.month, isEqualTo(month))
+                                .orderBy(SystemAttendanceDynamicSqlSupport.id.descending())
+                                .limit(1)
+                );
+                if (systemAttendanceOptional.isPresent()) {
+                    SystemAttendance lastSystemAttendance = systemAttendanceOptional.get();
+                    SystemAttendance systemAttendance = SystemAttendance.builder()
+                            .userId(user.getUserId())
+                            .lastScore(lastSystemAttendance.getCurrentScore())
+                            .changeScore(2)
+                            .currentScore(lastSystemAttendance.getCurrentScore() + 2)
+                            .month(month)
+                            .type(ATTENDANCE_TASK)
+                            .event("完成临时任务[" + task.getTitle() + "]得分")
+                            .createTime(now)
+                            .build();
+                    systemAttendances.add(systemAttendance);
+                }
+            }
+            if (!systemAttendances.isEmpty()) {
+                systemAttendanceExtMapper.insertMultiple(systemAttendances);
+            }
+        }
+        return task;
+    }
+
+    /**
+     * 分页查询临时任务
+     */
+    public PageInfo<TemporaryTaskVO> selectList(String title, Integer type, Integer status, Integer auditStatus, String content, String username, String executor, LocalDateTime startTime, LocalDateTime endTime, Integer page, Integer size, String order) {
+        order = SQLUtil.orderConvert(order);
+        PageSerializable<Long> pageSerializable = PageHelper.startPage(page, size).setOrderBy(order).doSelectPageSerializable(() -> temporaryTaskExtMapper.selectTaskIds(title, type, status, auditStatus, content, username, executor, startTime, endTime));
+        if (pageSerializable.getList().isEmpty()) {
+            return new PageInfo<>(pageSerializable.getTotal(), new ArrayList<>());
+        }
+        List<TemporaryTaskVO> temporaryTaskVOS = temporaryTaskExtMapper.selectListByTaskIds(pageSerializable.getList(), order);
+        return new PageInfo<>(pageSerializable.getTotal(), temporaryTaskVOS);
+    }
+
+    /**
+     * 我收到的临时任务统计
+     */
+    public List<TemporaryTaskStatusVO> selectReceiveStatisticalList() {
+        return temporaryTaskExtMapper.selectReceiveStatisticalListByUserId(curUserId());
+    }
+
+    /**
+     * 我发出的临时任务统计
+     */
+    public List<TemporaryTaskStatusVO> selectPublishStatisticalList() {
+        return temporaryTaskExtMapper.selectPublishStatisticalListByUserId(curUserId());
+    }
+
+    /**
+     * 我收到的临时任务列表
+     */
+    public PageInfo<TemporaryTaskVO> selectReceiveList(Integer status, Integer page, Integer size, String order) {
+        order = SQLUtil.orderConvert(order);
+        PageSerializable<Long> pageSerializable = PageHelper.startPage(page, size).setOrderBy(order).doSelectPageSerializable(() -> temporaryTaskExtMapper.selectTaskIdsByExecutor(status, curUserId()));
+        if (pageSerializable.getList().isEmpty()) {
+            return new PageInfo<>(pageSerializable.getTotal(), new ArrayList<>());
+        }
+        List<TemporaryTaskVO> temporaryTaskVOS = temporaryTaskExtMapper.selectListByTaskIds(pageSerializable.getList(), order);
+        return new PageInfo<>(pageSerializable.getTotal(), temporaryTaskVOS);
+    }
+
+    /**
+     * 我发出的任务列表
+     */
+    public PageInfo<TemporaryTaskVO> selectPublishList(Integer status, Integer page, Integer size, String order) {
+        order = SQLUtil.orderConvert(order);
+        PageSerializable<Long> pageSerializable = PageHelper.startPage(page, size).setOrderBy(order).doSelectPageSerializable(() -> temporaryTaskExtMapper.selectTaskIdsByPublisher(status, curUserId()));
+        if (pageSerializable.getList().isEmpty()) {
+            return new PageInfo<>(pageSerializable.getTotal(), new ArrayList<>());
+        }
+        List<TemporaryTaskVO> temporaryTaskVOS = temporaryTaskExtMapper.selectListByTaskIds(pageSerializable.getList(), order);
+        return new PageInfo<>(pageSerializable.getTotal(), temporaryTaskVOS);
+    }
+
+    /**
+     * 我收到的最新的一条任务
+     */
+    public TemporaryTaskVO queryNewest(Integer status) {
+        return temporaryTaskExtMapper.selectNewestByExecutor(curUserId(), status);
+    }
+}

+ 46 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/temporarytask/TemporaryTaskFeedbackExtService.java

@@ -0,0 +1,46 @@
+package com.chuanghai.patrol.service.temporarytask;
+
+import com.chuanghai.patrol.dao.TemporaryTaskFeedbackDynamicSqlSupport;
+import com.chuanghai.patrol.from.TemporaryTaskFeedbackAddFrom;
+import com.chuanghai.patrol.model.TemporaryTask;
+import com.chuanghai.patrol.model.TemporaryTaskFeedback;
+import com.chuanghai.patrol.service.mapper.temporarytask.TemporaryTaskExtMapper;
+import com.chuanghai.patrol.service.mapper.temporarytask.TemporaryTaskFeedbackExtMapper;
+import com.flyhigh.core.ApplicationContext;
+import com.flyhigh.core.exception.CustomizeException;
+import com.flyhigh.core.util.DateUtil;
+import lombok.RequiredArgsConstructor;
+import org.mybatis.dynamic.sql.SqlBuilder;
+import org.springframework.stereotype.Service;
+
+import static com.chuanghai.patrol.config.AppConstant.TEMPORARY_TASK_AUDIT_STATUS_PENDING_REVIEW;
+
+/**
+ * 临时任务反馈服务
+ */
+@Service
+@RequiredArgsConstructor
+public class TemporaryTaskFeedbackExtService extends ApplicationContext {
+    private final TemporaryTaskFeedbackExtMapper temporaryTaskFeedbackExtMapper;
+    private final TemporaryTaskExtMapper temporaryTaskExtMapper;
+
+    /**
+     * 添加临时任务反馈
+     */
+    public TemporaryTaskFeedback add(TemporaryTaskFeedbackAddFrom temporaryTaskFeedbackAddFrom) {
+        TemporaryTask task = temporaryTaskExtMapper.selectByPrimaryKey(temporaryTaskFeedbackAddFrom.getTaskId()).orElseThrow(() -> CustomizeException.exceptionClient("sys_data_does_not_exist"));
+        TemporaryTaskFeedback temporaryTaskFeedback = TemporaryTaskFeedback.builder()
+                .taskId(task.getId())
+                .userId(curUserId())
+                .content(temporaryTaskFeedbackAddFrom.getContent())
+                .images(temporaryTaskFeedbackAddFrom.getImages())
+                .createTime(DateUtil.now())
+                .build();
+        temporaryTaskFeedbackExtMapper.insertSelective(temporaryTaskFeedback);
+        long count = temporaryTaskFeedbackExtMapper.count(c -> c.where(TemporaryTaskFeedbackDynamicSqlSupport.taskId, SqlBuilder.isEqualTo(task.getId())));
+        task.setFeedbackTotal((int) count);
+        task.setAuditStatus(TEMPORARY_TASK_AUDIT_STATUS_PENDING_REVIEW);
+        temporaryTaskExtMapper.updateByPrimaryKey(task);
+        return temporaryTaskFeedback;
+    }
+}

+ 134 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/visitor/VisitorAuditExtService.java

@@ -0,0 +1,134 @@
+package com.chuanghai.patrol.service.visitor;
+
+import com.chuanghai.patrol.dao.VisitorAuditDynamicSqlSupport;
+import com.chuanghai.patrol.from.VisitorAuditAddFrom;
+import com.chuanghai.patrol.from.VisitorAuditUpdateFrom;
+import com.chuanghai.patrol.model.VisitorAudit;
+import com.chuanghai.patrol.service.mapper.visitor.VisitorAuditExtMapper;
+import com.chuanghai.patrol.vo.VisitorAuditVO;
+import com.flyhigh.core.ApplicationContext;
+import com.flyhigh.core.exception.CustomizeException;
+import com.flyhigh.core.util.DateUtil;
+import lombok.RequiredArgsConstructor;
+import org.mybatis.dynamic.sql.SqlBuilder;
+import org.springframework.stereotype.Service;
+
+import java.util.Calendar;
+import java.util.Optional;
+
+import static com.chuanghai.patrol.config.AppConstant.AUDIT_PASS;
+import static com.chuanghai.patrol.config.AppConstant.NOT_AUDIT;
+import static org.mybatis.dynamic.sql.SqlBuilder.isEqualTo;
+import static org.mybatis.dynamic.sql.SqlBuilder.or;
+
+/**
+ * 访客审批服务
+ */
+@Service
+@RequiredArgsConstructor
+public class VisitorAuditExtService extends ApplicationContext {
+    private final VisitorAuditExtMapper visitorAuditExtMapper;
+
+    /**
+     * 添加访客
+     */
+    public String add(VisitorAuditAddFrom visitorAuditAddFrom) {
+        // 未审核 更新审核资料
+        Optional<VisitorAudit> visitorOptional = visitorAuditExtMapper.selectOne(c ->
+                c.where(VisitorAuditDynamicSqlSupport.openid, isEqualTo(visitorAuditAddFrom.getOpenid()), or(VisitorAuditDynamicSqlSupport.userPhone, isEqualTo(visitorAuditAddFrom.getUserPhone())))
+                        .and(VisitorAuditDynamicSqlSupport.status, isEqualTo(NOT_AUDIT))
+        );
+        if (visitorOptional.isPresent()) {
+            VisitorAudit visitor = visitorOptional.get();
+            visitor.setUsername(visitorAuditAddFrom.getUsername())
+                    .setUserPhone(visitorAuditAddFrom.getUserPhone())
+                    .setCompany(visitorAuditAddFrom.getCompany())
+                    .setDuration(visitorAuditAddFrom.getDuration())
+                    .setItineraryCode(visitorAuditAddFrom.getItineraryCode())
+                    .setHealthCode(visitorAuditAddFrom.getHealthCode())
+                    .setHighRisk(visitorAuditAddFrom.getHighRisk())
+                    .setReason(visitorAuditAddFrom.getReason())
+                    .setInformation(visitorAuditAddFrom.getInformation());
+            visitorAuditExtMapper.updateByPrimaryKeySelective(visitor);
+            return "已更新提交信息";
+        } else {
+            // 已审核未出场 无法再次入场
+            visitorAuditExtMapper.selectOne(c ->
+                    c.where(VisitorAuditDynamicSqlSupport.openid, isEqualTo(visitorAuditAddFrom.getOpenid()), or(VisitorAuditDynamicSqlSupport.userPhone, isEqualTo(visitorAuditAddFrom.getUserPhone())))
+                            .and(VisitorAuditDynamicSqlSupport.status, isEqualTo(AUDIT_PASS))
+                            .and(VisitorAuditDynamicSqlSupport.leaveTime, SqlBuilder.isNull())
+            ).ifPresent(v -> {
+                throw CustomizeException.exceptionClient("请勿重复提交");
+            });
+            visitorOptional = visitorAuditExtMapper.selectOne(c -> c.orderBy(VisitorAuditDynamicSqlSupport.id.descending()).limit(1));
+            int number;
+            if (visitorOptional.isPresent()) {
+                number = visitorOptional.get().getNumber();
+                if (number / 10000 == Calendar.getInstance().get(Calendar.YEAR)) {
+                    number = Calendar.getInstance().get(Calendar.YEAR) * 10000 + number % 10000 + 1;
+                } else {
+                    number = Calendar.getInstance().get(Calendar.YEAR) * 10000 + 1;
+                }
+            } else {
+                number = Calendar.getInstance().get(Calendar.YEAR) * 10000 + 1;
+            }
+            VisitorAudit visitor = VisitorAudit.builder()
+                    .openid(visitorAuditAddFrom.getOpenid())
+                    .number(number)
+                    .username(visitorAuditAddFrom.getUsername())
+                    .userPhone(visitorAuditAddFrom.getUserPhone())
+                    .company(visitorAuditAddFrom.getCompany())
+                    .duration(visitorAuditAddFrom.getDuration())
+                    .itineraryCode(visitorAuditAddFrom.getItineraryCode())
+                    .healthCode(visitorAuditAddFrom.getHealthCode())
+                    .highRisk(visitorAuditAddFrom.getHighRisk())
+                    .reason(visitorAuditAddFrom.getReason())
+                    .status(NOT_AUDIT)
+                    .createTime(DateUtil.now())
+                    .information(visitorAuditAddFrom.getInformation())
+                    .build();
+            visitorAuditExtMapper.insertSelective(visitor);
+            return "提交成功";
+        }
+    }
+
+    /**
+     * 入场访客信息
+     */
+    public VisitorAuditVO query(String openid) {
+        VisitorAudit visitor = visitorAuditExtMapper.selectOne(c ->
+                c.where(VisitorAuditDynamicSqlSupport.openid, isEqualTo(openid))
+                        .and(VisitorAuditDynamicSqlSupport.status, isEqualTo(NOT_AUDIT), or(VisitorAuditDynamicSqlSupport.status, isEqualTo(AUDIT_PASS)))
+                        .and(VisitorAuditDynamicSqlSupport.leaveTime, SqlBuilder.isNull())
+        ).orElseThrow(() -> CustomizeException.exceptionClient("无法查找登记记录"));
+        if (visitor.getStatus().equals(NOT_AUDIT)) {
+            throw CustomizeException.exceptionClient("尚未审核,请联系相关部门");
+        }
+        return VisitorAuditVO.builder()
+                .id(visitor.getId())
+                .openid(visitor.getOpenid())
+                .username(visitor.getUsername())
+                .userPhone(visitor.getUserPhone())
+                .company(visitor.getCompany())
+                .entryTime(visitor.getEntryTime())
+                .reason(visitor.getReason())
+                .build();
+    }
+
+    /**
+     * 更新访客
+     */
+    public String update(VisitorAuditUpdateFrom visitorAuditUpdateFrom) {
+        VisitorAudit visitor = visitorAuditExtMapper.selectOne(c ->
+                c.where(VisitorAuditDynamicSqlSupport.id, isEqualTo(visitorAuditUpdateFrom.getId()))
+                        .and(VisitorAuditDynamicSqlSupport.status, isEqualTo(NOT_AUDIT), or(VisitorAuditDynamicSqlSupport.status, isEqualTo(AUDIT_PASS)))
+                        .and(VisitorAuditDynamicSqlSupport.leaveTime, SqlBuilder.isNull())
+        ).orElseThrow(() -> CustomizeException.exceptionClient("无法查找登记记录"));
+        if (visitor.getStatus().equals(NOT_AUDIT)) {
+            throw CustomizeException.exceptionClient("尚未审核,请联系相关部门");
+        }
+        visitor.setLeaveTime(DateUtil.now()).setRemark(visitorAuditUpdateFrom.getRemark());
+        visitorAuditExtMapper.updateByPrimaryKeySelective(visitor);
+        return "核销成功";
+    }
+}

+ 23 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/service/visitor/VisitorRegulationExtService.java

@@ -0,0 +1,23 @@
+package com.chuanghai.patrol.service.visitor;
+
+import com.chuanghai.patrol.model.VisitorRegulation;
+import com.chuanghai.patrol.service.mapper.visitor.VisitorRegulationExtMapper;
+import com.flyhigh.core.ApplicationContext;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+/**
+ * 制度管理服务
+ */
+@Service
+@RequiredArgsConstructor
+public class VisitorRegulationExtService extends ApplicationContext {
+    private final VisitorRegulationExtMapper visitorRegulationExtMapper;
+
+    /**
+     * 查询制度
+     */
+    public VisitorRegulation query() {
+        return visitorRegulationExtMapper.selectOne(c -> c.limit(1)).orElse(VisitorRegulation.builder().build());
+    }
+}

+ 37 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/util/wechat/WeChatUtil.java

@@ -0,0 +1,37 @@
+package com.chuanghai.patrol.util.wechat;
+
+import com.flyhigh.core.util.HttpUtil;
+import com.flyhigh.core.util.JsonUtil;
+import lombok.Data;
+import lombok.ToString;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@SuppressWarnings("unused")
+public class WeChatUtil {
+
+    public static final String USER_APPID = "wx67d29646ea3deb12"; // 用户端小程序appid
+    public static final String USER_SECRET = "d5f7940ae28ab2bb2afb2be466305f4b"; // 用户端小程序secret
+    public static final String GRANT_TYPE_CODE = "authorization_code"; // 授权类型 code码(必填)
+
+    // 获取session和openid
+    public static Session code2Session(String code) {
+        // 向微信服务器 使用登录凭证 code 获取 session_key 和 openid
+        String response = HttpUtil.doGet("https://api.weixin.qq.com/sns/jscode2session",
+                "appid", USER_APPID,
+                "secret", USER_SECRET,
+                "js_code", code,
+                "grant_type", GRANT_TYPE_CODE);
+        return JsonUtil.parseObject(response, Session.class);
+    }
+
+    @Data
+    @ToString
+    public static class Session {
+        private String openid; // Session
+        private String session_key; // 会话密钥
+        private String unionid; // 用户在开放平台的唯一标识符,在满足 UnionID 下发条件的情况下会返回,详见 UnionID 机制说明。
+        private String errcode; // 错误码
+        private String errmsg; // 错误信息
+    }
+}

+ 23 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/vo/CheckItemNumDetailsVO.java

@@ -0,0 +1,23 @@
+package com.chuanghai.patrol.vo;
+
+import com.chuanghai.patrol.model.CheckItem;
+import com.chuanghai.patrol.model.CheckItemExtraOfNum;
+import lombok.Builder;
+import lombok.Data;
+
+/**
+ * 数字项详情
+ */
+@Data
+@Builder
+public class CheckItemNumDetailsVO {
+    /**
+     * 检查项
+     */
+    private CheckItem checkItem;
+
+    /**
+     * 数字项额外信息
+     */
+    private CheckItemExtraOfNum extra;
+}

+ 0 - 0
applications/patrol/patrol-app/src/main/java/com/chuanghai/patrol/vo/CheckItemOptionVO.java


Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików