commit def60e21c75dc97560d35ab18cd94ce0e80cfdc6
Author: wxy <3050128610@qq.com>
Date: Fri Mar 6 14:01:32 2026 +0800
first commit
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ea5bf11
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,35 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+.log
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+application-prod.properties
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..9a9222c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,53 @@
+# 毕业设计
+一站式自动化运维及自动化部署平台, 使用多环境的概念, 提供了机器管理、机器监控报警、Web终端、WebSftp、机器批量执行、机器批量上传、在线查看日志、定时调度任务、应用环境维护、应用构建及发布任务、操作流水线等功能, 帮助企业实现一站式轻量化运维治理, 致力于企业级应用的智能运维。
+
+## 特性
+
+* 易用方便: 极简配置, 开箱即用, 支持 docker 部署
+* 在线终端: 支持在线 Web 终端, 记录操作日志, 管理员可强制下线, 录屏回放, 终端监视等
+* 文件管理: 支持远程机器文件批量上传、批量下载、暂停断点续传、实时传输速率、实时进度、打包传输等功能
+* 机器监控: 支持维护机器的监控以及报警, 支持采集 agent 的一键安装以及升级
+* 批量操作: 支持远程机器批量执行命令 以及 批量执行上传文件
+* 调度任务: 维护 cron 表达式, 定时执行机器命令
+* 环境隔离: 不同应用环境的配置及环境变量是相互隔离的
+* 环境变量: 命令执行时使用占位符自动替换, 支持 properties, json, yml, xml多种格式维护
+* 高兼容性: 自定义构建发布操作, 不论是什么项目都是配置 SSH 执行命令, 灵活操作
+* 功能强大: 命令批量执行, 任务定时调度, 远程日志查看, 操作日志全记录等
+* 高扩展性: 前后端代码规范统一, 代码健壮质量高, 写法优雅, 易读好拓展
+* 免费开源: 前后端代码完全开源, 方便二次开发
+
+## 技术栈
+
+* SpringBoot 2.4+
+* Mysql 8.+
+* Redis 5+
+* Vue 2.6+
+* Ant Design 1.7.8
+
+## 演示环境
+* 🔗 演示地址: https://bishe.youdu.xin
+* 🔏 演示账号: wxy/wxy
+* 注: 演示环境运行在宿舍电脑的虚拟机中, 每日早晨重置一次,半夜不提供演示服务
+
+## 功能预览
+
+### 控制台
+
+
+### 机器管理
+#### 机器列表
+
+
+#### 在线终端-连接演示
+Linux服务器
+
+H3C防火墙
+
+H3C交换机
+
+
+#### 终端日志-可回放审查
+终端日志总揽
+
+终端日志回放
+
\ No newline at end of file
diff --git a/orion-ops-api/orion-ops-common/pom.xml b/orion-ops-api/orion-ops-common/pom.xml
new file mode 100644
index 0000000..6df724e
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/pom.xml
@@ -0,0 +1,36 @@
+
+
+
+
+ cn.orionsec.ops
+ orion-ops-api
+ 1.3.1
+ ../pom.xml
+
+
+ orion-ops-common
+ orion-ops-common
+ 4.0.0
+
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+ cn.orionsec.kit
+ orion-all
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/annotation/DemoDisableApi.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/annotation/DemoDisableApi.java
new file mode 100644
index 0000000..f357227
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/annotation/DemoDisableApi.java
@@ -0,0 +1,10 @@
+package cn.orionsec.ops.annotation;
+
+import java.lang.annotation.*;
+
+
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface DemoDisableApi {
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/annotation/EventLog.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/annotation/EventLog.java
new file mode 100644
index 0000000..10d1c8d
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/annotation/EventLog.java
@@ -0,0 +1,19 @@
+
+package cn.orionsec.ops.annotation;
+
+import cn.orionsec.ops.constant.event.EventType;
+
+import java.lang.annotation.*;
+
+
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface EventLog {
+
+ /**
+ * @return 事件类型
+ */
+ EventType value();
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/annotation/IgnoreAuth.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/annotation/IgnoreAuth.java
new file mode 100644
index 0000000..2e3d25a
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/annotation/IgnoreAuth.java
@@ -0,0 +1,11 @@
+
+package cn.orionsec.ops.annotation;
+
+import java.lang.annotation.*;
+
+
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface IgnoreAuth {
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/annotation/IgnoreCheck.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/annotation/IgnoreCheck.java
new file mode 100644
index 0000000..f278f84
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/annotation/IgnoreCheck.java
@@ -0,0 +1,11 @@
+
+package cn.orionsec.ops.annotation;
+
+import java.lang.annotation.*;
+
+
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface IgnoreCheck {
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/annotation/IgnoreLog.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/annotation/IgnoreLog.java
new file mode 100644
index 0000000..e3e175f
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/annotation/IgnoreLog.java
@@ -0,0 +1,12 @@
+
+package cn.orionsec.ops.annotation;
+
+import java.lang.annotation.*;
+
+
+@SuppressWarnings("ALL")
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface IgnoreLog {
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/annotation/IgnoreWrapper.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/annotation/IgnoreWrapper.java
new file mode 100644
index 0000000..a8ee762
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/annotation/IgnoreWrapper.java
@@ -0,0 +1,11 @@
+
+package cn.orionsec.ops.annotation;
+
+import java.lang.annotation.*;
+
+
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface IgnoreWrapper {
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/annotation/RequireRole.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/annotation/RequireRole.java
new file mode 100644
index 0000000..8cd2b18
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/annotation/RequireRole.java
@@ -0,0 +1,21 @@
+
+package cn.orionsec.ops.annotation;
+
+import cn.orionsec.ops.constant.user.RoleType;
+
+import java.lang.annotation.*;
+
+
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface RequireRole {
+
+ /**
+ * 所需角色
+ *
+ * {@link RoleType}
+ */
+ RoleType[] value();
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/annotation/RestWrapper.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/annotation/RestWrapper.java
new file mode 100644
index 0000000..807c569
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/annotation/RestWrapper.java
@@ -0,0 +1,12 @@
+
+package cn.orionsec.ops.annotation;
+
+import java.lang.annotation.*;
+
+
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface RestWrapper {
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/CnConst.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/CnConst.java
new file mode 100644
index 0000000..4544a20
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/CnConst.java
@@ -0,0 +1,52 @@
+package cn.orionsec.ops.constant;
+
+public class CnConst {
+
+ private CnConst() {
+ }
+
+ public static final String ENABLE = "启用";
+
+ public static final String DISABLE = "停用";
+
+ public static final String RESOLVE = "通过";
+
+ public static final String REJECT = "驳回";
+
+ public static final String SUCCESS = "成功";
+
+ public static final String FAILURE = "失败";
+
+ public static final String OPEN = "开启";
+
+ public static final String CLOSE = "关闭";
+
+ public static final String YES = "是";
+
+ public static final String NO = "否";
+
+ public static final String APP = "应用";
+
+ public static final String RELEASE = "发布";
+
+ public static final String PASSWORD = "密码";
+
+ public static final String TOKEN = "令牌";
+
+ public static final String SECRET_KEY = "独立密钥";
+
+ public static final String READ = "已读";
+
+ public static final String UNREAD = "未读";
+
+ public static final String ORION_OPS_AUTHOR = "李佳航";
+
+ public static final String UNKNOWN = "未知";
+
+ public static final String INTRANET_IP = "内网IP";
+
+ public static final String INSTALL = "安装";
+
+ public static final String UPGRADE = "升级";
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/Const.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/Const.java
new file mode 100644
index 0000000..e71eb6c
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/Const.java
@@ -0,0 +1,184 @@
+package cn.orionsec.ops.constant;
+
+import cn.orionsec.kit.lang.utils.collect.Lists;
+
+import java.util.List;
+
+public class Const implements cn.orionsec.kit.lang.constant.Const {
+
+ private Const() {
+ }
+
+ public static final String ORION_OPS = "orion-ops";
+
+ public static final String KEYS_PATH = ".keys";
+
+ public static final String PIC_PATH = "pic";
+
+ public static final String SCREEN_PATH = "screen";
+
+ public static final String SWAP_PATH = "swap";
+
+ public static final String LOG_PATH = "logs";
+
+ public static final String TEMP_PATH = "temp";
+
+ public static final String REPO_PATH = "repo";
+
+ public static final String DIST_PATH = "dist";
+
+ public static final String MACHINE_MONITOR_AGENT_PATH = "/lib/machine-monitor-agent-latest.jar";
+
+ public static final String TAIL_FILE_PATH = "tail";
+
+ public static final String TERMINAL_DIR = "/terminal";
+
+ public static final String BUILD_DIR = "/build";
+
+ public static final String RELEASE_DIR = "/release";
+
+ public static final String RELEASE_MACHINE_PREFIX = "/machine";
+
+ public static final String EXEC_DIR = "/exec";
+
+ public static final String COMMAND_DIR = "/command";
+
+ public static final String AVATAR_DIR = "/avatar";
+
+ public static final String UPLOAD_DIR = "/upload";
+
+ public static final String DOWNLOAD_DIR = "/download";
+
+ public static final String PACKAGE_DIR = "/package";
+
+ public static final String EVENT_DIR = "/event";
+
+ public static final String TASK_DIR = "/task";
+
+ public static final String IMPORT_DIR = "/import";
+
+ public static final String EXPORT_DIR = "/export";
+
+ public static final String LIB_DIR = "/lib";
+
+ public static final String INSTALL_DIR = "/install";
+
+ public static final String BUILD = "build";
+
+ public static final String RELEASE = "release";
+
+ public static final String PIPELINE = "pipeline";
+
+ public static final String TASK = "task";
+
+ public static final String ACTION = "action";
+
+ public static final String ROOT = "root";
+
+ public static final String EVENT = "event";
+
+ public static final String PACKAGE = "package";
+
+ public static final String PLUGINS = "plugins";
+
+ public static final String TIMEOUT = "timeout";
+
+ public static final String CAST_SUFFIX = "cast";
+
+ public static final Integer FORBID_DELETE_CAN = 1;
+
+ public static final Integer FORBID_DELETE_NOT = 2;
+
+ public static final int EXEC_COMMAND_OMIT = 80;
+
+ public static final int TEMPLATE_OMIT = 80;
+
+ public static final int TAIL_OFFSET_LINE = 300;
+
+ public static final Long HOST_MACHINE_ID = 1L;
+
+ public static final Long ROOT_TREE_ID = -1L;
+
+ public static final Integer DEFAULT_TREE_SORT = 1;
+
+ public static final String HOST_MACHINE_TAG = "host";
+
+ public static final String SWAP_FILE_SUFFIX = ".swp";
+
+ public static final String SECRET_KEY_SUFFIX = "_id_rsa";
+
+ public static final Integer IS_DEFAULT = 1;
+
+ public static final Integer CONFIGURED = 1;
+
+ public static final Integer IS_SYSTEM = 1;
+
+ public static final Integer NOT_SYSTEM = 2;
+
+ public static final Integer NOT_CONFIGURED = 2;
+
+ public static final Integer COMMIT_LIMIT = 30;
+
+ public static final Integer BUILD_RELEASE_LIMIT = 20;
+
+ public static final String COPY = "Copy";
+
+ public static final String ROLLBACK = "Rollback";
+
+ public static final String COMPRESS_LIST_FILE = "压缩清单.txt";
+
+ public static final int TRACKER_DELAY_MS = 250;
+
+ public static final int MIN_TRACKER_DELAY_MS = 50;
+
+ public static final int DEFAULT_FILE_CLEAN_THRESHOLD = 60;
+
+ public static final int DEFAULT_LOGIN_TOKEN_EXPIRE_HOUR = 24 * 2;
+
+ public static final int SFTP_UPLOAD_THRESHOLD = 512;
+
+ public static final String GITHUB = "github";
+
+ public static final String GITEE = "gitee";
+
+ public static final String GITLAB = "gitlab";
+
+ public static final String OAUTH2 = "oauth2";
+
+ public static final String SOCKS4 = "socks4";
+
+ public static final String SOCKS5 = "socks5";
+
+ public static final String DEFAULT_SHELL = "/bin/bash";
+
+ public static final String LF_2 = "\n\n";
+
+ public static final String LF_3 = "\n\n\n";
+
+ public static final Integer ENABLE = 1;
+
+ public static final Integer DISABLE = 2;
+
+ public static final Integer NOT_DELETED = 1;
+
+ public static final Integer IS_DELETED = 2;
+
+ public static final Integer INCREMENT = 1;
+
+ public static final Integer DECREMENT = 2;
+
+ /**
+ * 不安全的文件夹
+ */
+ public static final List UNSAFE_FS_DIR = Lists.of(
+ "/", "/bin", "/usr",
+ "/sbin", "/etc", "/tmp",
+ "/lib", "/var", "/home",
+ "/opt", "/root", "/run",
+ "/lib64", "/lost+found", "/media",
+ "/mnt", "/proc", "/sys",
+ "/svr", "/dev", "/boot",
+ "/usr/bin", "/usr/include", "/usr/lib",
+ "/usr/local", "/usr/sbin", ".tmp");
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/KeyConst.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/KeyConst.java
new file mode 100644
index 0000000..0162a49
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/KeyConst.java
@@ -0,0 +1,156 @@
+package cn.orionsec.ops.constant;
+
+public class KeyConst {
+
+ private KeyConst() {
+ }
+
+ /**
+ * 登录 token
+ *
+ * auth:login:{id}
+ */
+ public static final String LOGIN_TOKEN_KEY = "auth:info:{}";
+
+ /**
+ * 登录 token 绑定 token
+ *
+ * auth:login:{id}:{timestamp}
+ */
+ public static final String LOGIN_TOKEN_BIND_KEY = "auth:bind:{}:{}";
+
+ /**
+ * terminal 访问 token
+ *
+ * terminal:access:{token}
+ */
+ public static final String TERMINAL_ACCESS_TOKEN = "terminal:access:{}";
+
+ /**
+ * 3min
+ */
+ public static final int TERMINAL_ACCESS_TOKEN_EXPIRE = 60 * 3;
+
+ /**
+ * terminal 监视 token
+ *
+ * terminal:watcher:{token}
+ */
+ public static final String TERMINAL_WATCHER_TOKEN = "terminal:watcher:{}";
+
+ /**
+ * 3min
+ */
+ public static final int TERMINAL_WATCHER_TOKEN_EXPIRE = 60 * 3;
+
+ /**
+ * 文件 tail 访问 token
+ *
+ * file:tail:access{token}
+ */
+ public static final String FILE_TAIL_ACCESS_TOKEN = "file:tail:access:{}";
+
+ /**
+ * 5 min
+ */
+ public static final int FILE_TAIL_ACCESS_EXPIRE = 60 * 5;
+
+ /**
+ * 文件下载 token
+ *
+ * file:download:{token}
+ */
+ public static final String FILE_DOWNLOAD_TOKEN = "file:download:{}";
+
+ /**
+ * 5 min
+ */
+ public static final int FILE_DOWNLOAD_EXPIRE = 60 * 5;
+
+ /**
+ * sftp 会话 token
+ *
+ * sftp:session:{token}
+ */
+ public static final String SFTP_SESSION_TOKEN = "sftp:session:{}";
+
+ /**
+ * 12 h
+ */
+ public static final int SFTP_SESSION_EXPIRE = 60 * 60 * 12;
+
+ /**
+ * sftp 上传请求 token
+ *
+ * sftp:upload:{token}
+ */
+ public static final String SFTP_UPLOAD_ACCESS_TOKEN = "sftp:upload:{}";
+
+ /**
+ * 5 h
+ */
+ public static final int SFTP_UPLOAD_ACCESS_EXPIRE = 60 * 60 * 5;
+
+ /**
+ * 主页统计数量 key
+ *
+ * data:statistics:home:count:{profileId}
+ */
+ public static final String HOME_STATISTICS_COUNT_KEY = "data:statistics:home:count:{}";
+
+ /**
+ * 调度任务统计 key
+ *
+ * data:statistics:scheduler:task:{id}
+ */
+ public static final String SCHEDULER_TASK_STATISTICS_KEY = "data:statistics:scheduler:task:{}";
+
+ /**
+ * 环境缓存 key
+ *
+ * data:profile
+ */
+ public static final String DATA_PROFILE_KEY = "data:profile";
+
+ /**
+ * 30 min
+ */
+ public static final int DATA_PROFILE_EXPIRE = 60 * 30;
+
+ /**
+ * 数据导入缓存 key
+ *
+ * data:import:{userId}:{token}
+ */
+ public static final String DATA_IMPORT_TOKEN = "data:import:{}:{}";
+
+ /**
+ * 5 min
+ */
+ public static final int DATA_IMPORT_TOKEN_EXPIRE = 60 * 5;
+
+ /**
+ * 机器分组数据 key
+ *
+ * machine:group:data
+ */
+ public static final String MACHINE_GROUP_DATA_KEY = "machine:group:data";
+
+ /**
+ * 5 h
+ */
+ public static final int MACHINE_GROUP_DATA_EXPIRE = 60 * 60 * 5;
+
+ /**
+ * 机器分组引用 key
+ *
+ * machine:group:rel
+ */
+ public static final String MACHINE_GROUP_REL_KEY = "machine:group:rel";
+
+ /**
+ * 5 h
+ */
+ public static final int MACHINE_GROUP_REL_EXPIRE = 60 * 60 * 5;
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/MessageConst.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/MessageConst.java
new file mode 100644
index 0000000..9d26264
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/MessageConst.java
@@ -0,0 +1,231 @@
+package cn.orionsec.ops.constant;
+
+
+public class MessageConst {
+
+ private MessageConst() {
+ }
+
+ public static final String ABSENT = "不存在";
+
+ public static final String UNAUTHORIZED = "会话过期";
+
+ public static final String NO_PERMISSION = "无操作权限";
+
+ public static final String FILE_MISSING = "文件不存在";
+
+ public static final String IP_BAN = "当前IP已被封禁";
+
+ public static final String ILLEGAL_ACCESS = "非法访问";
+
+ public static final String ABSENT_PARAM = "参数缺失";
+
+ public static final String INVALID_PARAM = "非法参数";
+
+ public static final String PARSE_ERROR = "解析失败";
+
+ public static final String OPERATOR_ERROR = "操作失败";
+
+ public static final String DEMO_DISABLE_API = "演示模式不支持此功能";
+
+ public static final String HTTP_API = "api 调用异常";
+
+ public static final String NETWORK_FLUCTUATION = "当前环境网路波动";
+
+ public static final String OPEN_TEMPLATE_ERROR = "模板解析失败 请检查模板和密码";
+
+ public static final String PARSE_TEMPLATE_DATA_ERROR = "模板解析失败 请检查模板数据";
+
+ public static final String REPOSITORY_OPERATOR_ERROR = "应用版本仓库操作执行失败";
+
+ public static final String TASK_ERROR = "任务执行异常";
+
+ public static final String CONNECT_ERROR = "建立连接失败";
+
+ public static final String TIMEOUT_ERROR = "处理超时";
+
+ public static final String INTERRUPT_ERROR = "操作中断";
+
+ public static final String USERNAME_PASSWORD_ERROR = "用户名或密码错误";
+
+ public static final String USER_DISABLED = "用户已被禁用";
+
+ public static final String USER_LOCKED = "用户已被锁定";
+
+ public static final String UNKNOWN_USER = "未查询到用户信息";
+
+ public static final String USERNAME_PRESENT = "用户名已存在";
+
+ public static final String BEFORE_PASSWORD_EMPTY = "原密码为空";
+
+ public static final String BEFORE_PASSWORD_ERROR = "原密码错误";
+
+ public static final String UNSAFE_OPERATOR = "不安全的操作";
+
+ public static final String UNSUPPORTED_OPERATOR = "不支持的操作";
+
+ public static final String ENCRYPT_ERROR = "数据加密异常";
+
+ public static final String DECRYPT_ERROR = "数据解密异常";
+
+ public static final String UNKNOWN_DATA = "未查询到数据";
+
+ public static final String UNKNOWN_EXPORT_TYPE = "未知的导出类型";
+
+ public static final String INVALID_MACHINE = "未知的机器";
+
+ public static final String MACHINE_DISABLE = "机器未启用";
+
+ public static final String INVALID_PROXY = "未查询到代理信息";
+
+ public static final String INVALID_PTY = "终端类型不合法";
+
+ public static final String EXCEPTION_MESSAGE = "系统异常";
+
+ public static final String AUTH_EXCEPTION_MESSAGE = "认证失败";
+
+ public static final String TIMEOUT_EXCEPTION_MESSAGE = "连接超时";
+
+ public static final String IO_EXCEPTION_MESSAGE = "网络异常";
+
+ public static final String SQL_EXCEPTION_MESSAGE = "数据异常";
+
+ public static final String UNCONNECTED = "未建立连接";
+
+ public static final String EXEC_TASK_ABSENT = "未查询到任务信息";
+
+ public static final String EXEC_TASK_THREAD_ABSENT = "未查询到任务进程";
+
+ public static final String TEMPLATE_ABSENT = "未查询到模板信息";
+
+ public static final String HISTORY_VALUE_ABSENT = "未查询到历史值信息";
+
+ public static final String METADATA_ABSENT = "元数据缺失";
+
+ public static final String ENV_ABSENT = "环境变量不存在";
+
+ public static final String TOKEN_EMPTY = "token为空";
+
+ public static final String TOKEN_EXPIRE = "token过期";
+
+ public static final String SESSION_EXPIRE = "会话过期";
+
+ public static final String PATH_NOT_NORMALIZE = "路径不合法";
+
+ public static final String FILE_NOT_FOUND = "文件 {} 不存在";
+
+ public static final String TRANSFER_ITEM_EMPTY = "未找到可传输对象";
+
+ public static final String UNSELECTED_TRANSFER_LOG = "未找到传输对象";
+
+ public static final String FILE_TOO_LARGE = "文件过大";
+
+ public static final String NAME_PRESENT = "名称重复";
+
+ public static final String TAG_PRESENT = "唯一标识重复";
+
+ public static final String FORBID_DELETE = "禁止删除";
+
+ public static final String APP_ABSENT = "应用不存在";
+
+ public static final String PROFILE_ABSENT = "环境不存在";
+
+ public static final String CONFIG_ABSENT = "配置不存在";
+
+ public static final String APP_PROFILE_NOT_CONFIGURED = "应用环境还未配置";
+
+ public static final String CHECKOUT_ACTION_PRESENT = "检出操作只能有一个";
+
+ public static final String TRANSFER_ACTION_PRESENT = "传输操作只能有一个";
+
+ public static final String ILLEGAL_MACHINE_SECRET_KEY = "密钥不合法, 请检查密码或使用 ssh-keygen -m PEM -t rsa 重新生成";
+
+ public static final String AUTO_AUDIT_RESOLVE = "自动审核通过";
+
+ public static final String AUDIT_NOT_REQUIRED = "无需审核";
+
+ public static final String RELEASE_ABSENT = "发布任务不存在";
+
+ public static final String RELEASE_MACHINE_ABSENT = "发布机器不存在";
+
+ public static final String OPERATOR_NOT_ALL_SUCCESS = "未全部执行成功";
+
+ public static final String UNKNOWN_RELEASE_MACHINE = "未知的发布机器";
+
+ public static final String ILLEGAL_STATUS = "当前状态不支持此操作";
+
+ public static final String FILE_ABSENT_UNABLE_ROLLBACK = "产物丢失无法回滚";
+
+ public static final String REPO_INIT_ERROR = "仓库初始化失败";
+
+ public static final String REPO_PATH_ABSENT = "仓库目录不存在";
+
+ public static final String REPO_UNABLE_CONNECT = "无法连接到远程仓库";
+
+ public static final String REPO_UNINITIALIZED = "仓库未初始化";
+
+ public static final String REPO_INITIALIZED = "远程仓库已初始化";
+
+ public static final String REPO_INITIALIZING = "远程仓库初始化中";
+
+ public static final String CHECKOUT_ERROR = "git clone 检出失败";
+
+ public static final String RESET_ERROR = "git reset 操作失败";
+
+ public static final String BUILD_ABSENT = "构建版本不存在";
+
+ public static final String BUNDLE_FILE_ABSENT = "构建产物不存在";
+
+ public static final String BUNDLE_ZIP_FILE_ABSENT = "构建产物压缩文件不存在";
+
+ public static final String UNABLE_CONFIG_RELEASE_MACHINE = "发布机器未配置";
+
+ public static final String NO_SUCH_FILE = "未找到文件或目录";
+
+ public static final String TASK_ABSENT = "任务不存在";
+
+ public static final String TASK_PRESENT = "任务已存在";
+
+ public static final String INVALID_CONFIG = "配置不合法";
+
+ public static final String ERROR_EXPRESSION = "表达式错误";
+
+ public static final String TIMED_GREATER_THAN_NOW = "定时操作时间不能小于当前时间";
+
+ public static final String TASK_NOT_ENABLED = "调度任务未启用";
+
+ public static final String SESSION_PRESENT = "会话不存在";
+
+ public static final String UPLOAD_TOO_LARGE = "上传文件大小不能大于 {}MB, 当前大小 {}";
+
+ public static final String PIPELINE_ABSENT = "流水线不存在";
+
+ public static final String PIPELINE_TASK_ABSENT = "流水线任务不存在";
+
+ public static final String PIPELINE_DETAIL_EMPTY = "流水线操作为空";
+
+ public static final String PIPELINE_DETAIL_ABSENT = "未查询到流水线操作";
+
+ public static final String APP_LAST_BUILD_VERSION_ABSENT = "{} 无构建版本";
+
+ public static final String EXECUTE_SFTP_ZIP_COMMAND_ERROR = "执行 zip 压缩命令失败";
+
+ public static final String SFTP_ZIP_FILE_ABSENT = "压缩文件不存在";
+
+ public static final String OPERATOR_TIMEOUT = "操作超时";
+
+ public static final String UNKNOWN_MACHINE_TAG = "未查询到机器: {}";
+
+ public static final String UNKNOWN_MACHINE_KEY = "未查询到机器密钥: {}";
+
+ public static final String UNKNOWN_APP_REPOSITORY = "未查询到应用仓库: {}";
+
+ public static final String AGENT_STATUS_IS_STARTING = "插件正在启动中";
+
+ public static final String AGENT_FILE_NON_EXIST = "插件包不存在 请参考文档并移动到: {}";
+
+ public static final String WEBHOOK_ABSENT = "webhook 不存在";
+
+ public static final String ALARM_GROUP_ABSENT = "报警组不存在";
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/ParamConst.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/ParamConst.java
new file mode 100644
index 0000000..fe34b9d
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/ParamConst.java
@@ -0,0 +1,14 @@
+package cn.orionsec.ops.constant;
+
+public class ParamConst {
+
+ private ParamConst() {
+ }
+
+ public static final String LIMIT = "limit";
+
+ public static final String NAME = "name";
+
+ public static final String MACHINE_ID = "machineId";
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/PropertiesConst.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/PropertiesConst.java
new file mode 100644
index 0000000..c6cdd92
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/PropertiesConst.java
@@ -0,0 +1,49 @@
+package cn.orionsec.ops.constant;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+@Component
+public class PropertiesConst {
+
+ /**
+ * 当前版本
+ */
+ public static String ORION_OPS_VERSION;
+
+ /**
+ * 登录 token 请求头
+ */
+ public static String LOGIN_TOKEN_HEADER;
+
+ /**
+ * 加密密钥
+ */
+ public static String VALUE_MIX_SECRET_KEY;
+
+ /**
+ * 机器监控插件最新版本
+ */
+ public static String MACHINE_MONITOR_LATEST_VERSION;
+
+ @Value("${app.version}")
+ private void setVersion(String version) {
+ PropertiesConst.ORION_OPS_VERSION = version;
+ }
+
+ @Value("${login.token.header}")
+ private void setLoginTokenHeader(String loginTokenHeader) {
+ PropertiesConst.LOGIN_TOKEN_HEADER = loginTokenHeader;
+ }
+
+ @Value("${value.mix.secret.key}")
+ private void setValueMixSecretKey(String valueMixSecretKey) {
+ PropertiesConst.VALUE_MIX_SECRET_KEY = valueMixSecretKey;
+ }
+
+ @Value("${machine.monitor.latest.version}")
+ private void setMachineMonitorLatestVersion(String agentVersion) {
+ PropertiesConst.MACHINE_MONITOR_LATEST_VERSION = agentVersion;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/ResultCode.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/ResultCode.java
new file mode 100644
index 0000000..7fac52f
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/ResultCode.java
@@ -0,0 +1,63 @@
+package cn.orionsec.ops.constant;
+
+import cn.orionsec.kit.lang.define.wrapper.CodeInfo;
+
+public enum ResultCode implements CodeInfo {
+
+ /**
+ * 未认证
+ */
+ UNAUTHORIZED(700, MessageConst.UNAUTHORIZED),
+
+ /**
+ * 无权限
+ */
+ NO_PERMISSION(710, MessageConst.NO_PERMISSION),
+
+ /**
+ * 文件未找到
+ */
+ FILE_MISSING(720, MessageConst.FILE_MISSING),
+
+ /**
+ * IP封禁
+ */
+ IP_BAN(730, MessageConst.IP_BAN),
+
+ /**
+ * 用户禁用
+ */
+ USER_DISABLED(740, MessageConst.USER_DISABLED),
+
+ /**
+ * 非法访问
+ */
+ ILLEGAL_ACCESS(750, MessageConst.ILLEGAL_ACCESS),
+
+ /**
+ * 演示模式不支持此功能
+ */
+ DEMO_DISABLE_API(760, MessageConst.DEMO_DISABLE_API),
+
+ ;
+
+ private final int code;
+
+ private final String message;
+
+ ResultCode(int code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+
+ @Override
+ public int code() {
+ return code;
+ }
+
+ @Override
+ public String message() {
+ return message;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/SchedulerPools.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/SchedulerPools.java
new file mode 100644
index 0000000..5236ebd
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/SchedulerPools.java
@@ -0,0 +1,245 @@
+package cn.orionsec.ops.constant;
+
+import cn.orionsec.kit.lang.define.thread.ExecutorBuilder;
+import cn.orionsec.kit.lang.utils.Systems;
+import cn.orionsec.kit.lang.utils.Threads;
+
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+
+public class SchedulerPools {
+
+ private SchedulerPools() {
+ }
+
+ /**
+ * terminal 调度线程池
+ */
+ public static final ThreadPoolExecutor TERMINAL_SCHEDULER = ExecutorBuilder.create()
+ .namedThreadFactory("terminal-thread-")
+ .corePoolSize(1)
+ .maxPoolSize(Integer.MAX_VALUE)
+ .keepAliveTime(Const.MS_S_60)
+ .workQueue(new SynchronousQueue<>())
+ .allowCoreThreadTimeout(true)
+ .build();
+
+ /**
+ * terminal watcher 调度线程池
+ */
+ public static final ThreadPoolExecutor TERMINAL_WATCHER_SCHEDULER = ExecutorBuilder.create()
+ .namedThreadFactory("terminal-watcher-thread-")
+ .corePoolSize(0)
+ .maxPoolSize(Integer.MAX_VALUE)
+ .keepAliveTime(Const.MS_S_30)
+ .workQueue(new SynchronousQueue<>())
+ .allowCoreThreadTimeout(true)
+ .build();
+
+ /**
+ * 命令执行 调度线程池
+ */
+ public static final ThreadPoolExecutor EXEC_SCHEDULER = ExecutorBuilder.create()
+ .namedThreadFactory("exec-thread-")
+ .corePoolSize(1)
+ .maxPoolSize(Integer.MAX_VALUE)
+ .keepAliveTime(Const.MS_S_30)
+ .workQueue(new SynchronousQueue<>())
+ .allowCoreThreadTimeout(true)
+ .build();
+
+ /**
+ * tail 调度线程池
+ */
+ public static final ThreadPoolExecutor TAIL_SCHEDULER = ExecutorBuilder.create()
+ .namedThreadFactory("tail-thread-")
+ .corePoolSize(1)
+ .maxPoolSize(Integer.MAX_VALUE)
+ .keepAliveTime(Const.MS_S_60)
+ .workQueue(new SynchronousQueue<>())
+ .allowCoreThreadTimeout(true)
+ .build();
+
+
+ /**
+ * sftp 传输进度线程池
+ */
+ public static final ThreadPoolExecutor SFTP_TRANSFER_RATE_SCHEDULER = ExecutorBuilder.create()
+ .namedThreadFactory("sftp-transfer-rate-thread-")
+ .corePoolSize(1)
+ .maxPoolSize(Integer.MAX_VALUE)
+ .keepAliveTime(Const.MS_S_30)
+ .workQueue(new SynchronousQueue<>())
+ .allowCoreThreadTimeout(true)
+ .build();
+
+
+ /**
+ * sftp 上传线程池
+ */
+ public static final ThreadPoolExecutor SFTP_UPLOAD_SCHEDULER = ExecutorBuilder.create()
+ .namedThreadFactory("sftp-upload-thread-")
+ .corePoolSize(6)
+ .maxPoolSize(6)
+ .keepAliveTime(Const.MS_S_60)
+ .workQueue(new LinkedBlockingQueue<>())
+ .allowCoreThreadTimeout(true)
+ .build();
+
+ /**
+ * sftp 下载线程池
+ */
+ public static final ThreadPoolExecutor SFTP_DOWNLOAD_SCHEDULER = ExecutorBuilder.create()
+ .namedThreadFactory("sftp-download-thread-")
+ .corePoolSize(6)
+ .maxPoolSize(6)
+ .keepAliveTime(Const.MS_S_60)
+ .workQueue(new LinkedBlockingQueue<>())
+ .allowCoreThreadTimeout(true)
+ .build();
+
+ /**
+ * sftp 打包线程池
+ */
+ public static final ThreadPoolExecutor SFTP_PACKAGE_SCHEDULER = ExecutorBuilder.create()
+ .namedThreadFactory("sftp-package-thread-")
+ .corePoolSize(4)
+ .maxPoolSize(4)
+ .keepAliveTime(Const.MS_S_60)
+ .workQueue(new LinkedBlockingQueue<>())
+ .allowCoreThreadTimeout(true)
+ .build();
+
+ /**
+ * 应用构建线程池
+ */
+ public static final ThreadPoolExecutor APP_BUILD_SCHEDULER = ExecutorBuilder.create()
+ .namedThreadFactory("app-build-thread-")
+ .corePoolSize(1)
+ .maxPoolSize(Integer.MAX_VALUE)
+ .keepAliveTime(Const.MS_S_30)
+ .workQueue(new SynchronousQueue<>())
+ .allowCoreThreadTimeout(true)
+ .build();
+
+ /**
+ * 应用发布 主线程操作线程池
+ */
+ public static final ThreadPoolExecutor RELEASE_MAIN_SCHEDULER = ExecutorBuilder.create()
+ .namedThreadFactory("release-main-thread-")
+ .corePoolSize(1)
+ .maxPoolSize(Integer.MAX_VALUE)
+ .keepAliveTime(Const.MS_S_30)
+ .workQueue(new SynchronousQueue<>())
+ .allowCoreThreadTimeout(true)
+ .build();
+
+ /**
+ * 应用发布 机器操作线程池
+ */
+ public static final ThreadPoolExecutor RELEASE_MACHINE_SCHEDULER = ExecutorBuilder.create()
+ .namedThreadFactory("release-machine-thread-")
+ .corePoolSize(1)
+ .maxPoolSize(Integer.MAX_VALUE)
+ .keepAliveTime(Const.MS_S_30)
+ .workQueue(new SynchronousQueue<>())
+ .allowCoreThreadTimeout(true)
+ .build();
+
+ /**
+ * 调度任务 主进程操作线程池
+ */
+ public static final ThreadPoolExecutor SCHEDULER_TASK_MAIN_SCHEDULER = ExecutorBuilder.create()
+ .namedThreadFactory("scheduler-task-main-thread-")
+ .corePoolSize(1)
+ .maxPoolSize(Integer.MAX_VALUE)
+ .keepAliveTime(Const.MS_S_30)
+ .workQueue(new SynchronousQueue<>())
+ .allowCoreThreadTimeout(true)
+ .build();
+
+ /**
+ * 调度任务 机器操作线程池
+ */
+ public static final ThreadPoolExecutor SCHEDULER_TASK_MACHINE_SCHEDULER = ExecutorBuilder.create()
+ .namedThreadFactory("scheduler-task-machine-thread-")
+ .corePoolSize(1)
+ .maxPoolSize(Integer.MAX_VALUE)
+ .keepAliveTime(Const.MS_S_30)
+ .workQueue(new SynchronousQueue<>())
+ .allowCoreThreadTimeout(true)
+ .build();
+
+ /**
+ * 应用流水线 线程池
+ */
+ public static final ThreadPoolExecutor PIPELINE_SCHEDULER = ExecutorBuilder.create()
+ .namedThreadFactory("pipeline-thread-")
+ .corePoolSize(1)
+ .maxPoolSize(Integer.MAX_VALUE)
+ .keepAliveTime(Const.MS_S_30)
+ .workQueue(new SynchronousQueue<>())
+ .allowCoreThreadTimeout(true)
+ .build();
+
+ /**
+ * 异步导入 线程池
+ */
+ public static final ThreadPoolExecutor ASYNC_IMPORT_SCHEDULER = ExecutorBuilder.create()
+ .namedThreadFactory("async-import-thread-")
+ .corePoolSize(1)
+ .maxPoolSize(4)
+ .keepAliveTime(Const.MS_S_30)
+ .workQueue(new LinkedBlockingQueue<>())
+ .allowCoreThreadTimeout(true)
+ .build();
+
+ /**
+ * 插件安装 线程池
+ */
+ public static final ThreadPoolExecutor AGENT_INSTALL_SCHEDULER = ExecutorBuilder.create()
+ .namedThreadFactory("agent-install-thread-")
+ .corePoolSize(4)
+ .maxPoolSize(4)
+ .keepAliveTime(Const.MS_S_30)
+ .workQueue(new LinkedBlockingQueue<>())
+ .allowCoreThreadTimeout(true)
+ .build();
+
+ /**
+ * 机器报警 线程池
+ */
+ public static final ThreadPoolExecutor MACHINE_ALARM_SCHEDULER = ExecutorBuilder.create()
+ .namedThreadFactory("machine-alarm-thread-")
+ .corePoolSize(1)
+ .maxPoolSize(Integer.MAX_VALUE)
+ .keepAliveTime(Const.MS_S_30)
+ .workQueue(new SynchronousQueue<>())
+ .allowCoreThreadTimeout(true)
+ .build();
+
+
+ static {
+ Systems.addShutdownHook(() -> {
+ Threads.shutdownPoolNow(TERMINAL_SCHEDULER, Const.MS_S_3);
+ Threads.shutdownPoolNow(TERMINAL_WATCHER_SCHEDULER, Const.MS_S_3);
+ Threads.shutdownPoolNow(EXEC_SCHEDULER, Const.MS_S_3);
+ Threads.shutdownPoolNow(TAIL_SCHEDULER, Const.MS_S_3);
+ Threads.shutdownPoolNow(SFTP_TRANSFER_RATE_SCHEDULER, Const.MS_S_3);
+ Threads.shutdownPoolNow(SFTP_UPLOAD_SCHEDULER, Const.MS_S_3);
+ Threads.shutdownPoolNow(SFTP_DOWNLOAD_SCHEDULER, Const.MS_S_3);
+ Threads.shutdownPoolNow(SFTP_PACKAGE_SCHEDULER, Const.MS_S_3);
+ Threads.shutdownPoolNow(APP_BUILD_SCHEDULER, Const.MS_S_3);
+ Threads.shutdownPoolNow(RELEASE_MAIN_SCHEDULER, Const.MS_S_3);
+ Threads.shutdownPoolNow(RELEASE_MACHINE_SCHEDULER, Const.MS_S_3);
+ Threads.shutdownPoolNow(SCHEDULER_TASK_MAIN_SCHEDULER, Const.MS_S_3);
+ Threads.shutdownPoolNow(SCHEDULER_TASK_MACHINE_SCHEDULER, Const.MS_S_3);
+ Threads.shutdownPoolNow(PIPELINE_SCHEDULER, Const.MS_S_3);
+ Threads.shutdownPoolNow(ASYNC_IMPORT_SCHEDULER, Const.MS_S_3);
+ Threads.shutdownPoolNow(AGENT_INSTALL_SCHEDULER, Const.MS_S_3);
+ Threads.shutdownPoolNow(MACHINE_ALARM_SCHEDULER, Const.MS_S_3);
+ });
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/alarm/AlarmGroupNotifyType.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/alarm/AlarmGroupNotifyType.java
new file mode 100644
index 0000000..8ca9ab5
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/alarm/AlarmGroupNotifyType.java
@@ -0,0 +1,33 @@
+
+package cn.orionsec.ops.constant.alarm;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+
+@Getter
+@AllArgsConstructor
+public enum AlarmGroupNotifyType {
+
+ /**
+ * webhook 通知
+ */
+ WEBHOOK(10),
+
+ ;
+
+ private final Integer type;
+
+ public static AlarmGroupNotifyType of(Integer type) {
+ if (type == null) {
+ return null;
+ }
+ for (AlarmGroupNotifyType value : values()) {
+ if (value.type.equals(type)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/ActionStatus.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/ActionStatus.java
new file mode 100644
index 0000000..355e57f
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/ActionStatus.java
@@ -0,0 +1,58 @@
+
+package cn.orionsec.ops.constant.app;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+
+@AllArgsConstructor
+@Getter
+public enum ActionStatus {
+
+ /**
+ * 未开始
+ */
+ WAIT(10),
+
+ /**
+ * 进行中
+ */
+ RUNNABLE(20),
+
+ /**
+ * 已完成
+ */
+ FINISH(30),
+
+ /**
+ * 执行失败
+ */
+ FAILURE(40),
+
+ /**
+ * 已跳过
+ */
+ SKIPPED(50),
+
+ /**
+ * 已终止
+ */
+ TERMINATED(60),
+
+ ;
+
+ private final Integer status;
+
+ public static ActionStatus of(Integer status) {
+ if (status == null) {
+ return null;
+ }
+ for (ActionStatus value : values()) {
+ if (value.status.equals(status)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/ActionType.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/ActionType.java
new file mode 100644
index 0000000..26f882c
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/ActionType.java
@@ -0,0 +1,104 @@
+
+package cn.orionsec.ops.constant.app;
+
+import lombok.Getter;
+
+
+@Getter
+public enum ActionType {
+
+ /**
+ * 构建-检出代码
+ */
+ BUILD_CHECKOUT(110, StageType.BUILD),
+
+ /**
+ * 构建-机器命令
+ */
+ BUILD_COMMAND(120, StageType.BUILD),
+
+ /**
+ * 发布-传输产物
+ */
+ RELEASE_TRANSFER(210, StageType.RELEASE),
+
+ /**
+ * 发布-机器命令
+ */
+ RELEASE_COMMAND(220, StageType.RELEASE),
+
+ ;
+
+ private final Integer type;
+
+ private final StageType stage;
+
+ private final Integer stageType;
+
+ ActionType(Integer type, StageType stage) {
+ this.type = type;
+ this.stage = stage;
+ this.stageType = stage.getType();
+ }
+
+ public static ActionType of(Integer type) {
+ if (type == null) {
+ return null;
+ }
+ for (ActionType value : values()) {
+ if (value.type.equals(type)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+ public static ActionType of(Integer type, Integer stageType) {
+ if (type == null) {
+ return null;
+ }
+ for (ActionType value : values()) {
+ if (value.type.equals(type) && value.stageType.equals(stageType)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * 是否是构建action
+ *
+ * @param type type
+ * @return res
+ */
+ public static boolean isBuildAction(Integer type) {
+ if (type == null) {
+ return false;
+ }
+ for (ActionType value : values()) {
+ if (value.type.equals(type)) {
+ return StageType.BUILD.equals(value.stage);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * 是否是发布action
+ *
+ * @param type type
+ * @return res
+ */
+ public static boolean isReleaseAction(Integer type) {
+ if (type == null) {
+ return false;
+ }
+ for (ActionType value : values()) {
+ if (value.type.equals(type)) {
+ return StageType.RELEASE.equals(value.stage);
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/ApplicationEnvAttr.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/ApplicationEnvAttr.java
new file mode 100644
index 0000000..f34e5c7
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/ApplicationEnvAttr.java
@@ -0,0 +1,85 @@
+
+package cn.orionsec.ops.constant.app;
+
+import cn.orionsec.ops.constant.common.ExceptionHandlerType;
+import cn.orionsec.ops.constant.common.SerialType;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+
+@Getter
+public enum ApplicationEnvAttr {
+
+ /**
+ * 构建产物路径
+ */
+ BUNDLE_PATH("宿主机构建产物路径 (绝对路径/基于版本仓库的相对路径)"),
+
+ /**
+ * 产物传输路径
+ */
+ TRANSFER_PATH("产物传输目标机器绝对路径"),
+
+ /**
+ * 产物传输方式 (sftp/scp)
+ *
+ * @see TransferMode
+ */
+ TRANSFER_MODE("产物传输方式 (sftp/scp)"),
+
+ /**
+ * 产物传输文件类型 (normal/zip)
+ *
+ * @see TransferFileType
+ */
+ TRANSFER_FILE_TYPE("产物传输文件类型 (normal/zip)"),
+
+ /**
+ * 发布序列方式
+ *
+ * @see SerialType
+ */
+ RELEASE_SERIAL("发布序列方式 (serial/parallel)"),
+
+ /**
+ * 异常处理类型
+ *
+ * @see SerialType#SERIAL
+ * @see ExceptionHandlerType
+ */
+ EXCEPTION_HANDLER("异常处理类型 (skip_all/skip_error)"),
+
+ /**
+ * 构建序列号
+ */
+ BUILD_SEQ("构建序列号 (自增)"),
+
+ ;
+
+ /**
+ * key
+ */
+ private final String key;
+
+ /**
+ * 描述
+ */
+ private final String description;
+
+ ApplicationEnvAttr(String description) {
+ this.description = description;
+ this.key = this.name().toLowerCase();
+ }
+
+ public static ApplicationEnvAttr of(String key) {
+ if (key == null) {
+ return null;
+ }
+ return Arrays.stream(values())
+ .filter(a -> a.key.equals(key))
+ .findFirst()
+ .orElse(null);
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/BuildStatus.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/BuildStatus.java
new file mode 100644
index 0000000..da1bbbf
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/BuildStatus.java
@@ -0,0 +1,52 @@
+
+package cn.orionsec.ops.constant.app;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public enum BuildStatus {
+
+ /**
+ * 未开始
+ */
+ WAIT(10),
+
+ /**
+ * 进行中
+ */
+ RUNNABLE(20),
+
+ /**
+ * 已完成
+ */
+ FINISH(30),
+
+ /**
+ * 执行失败
+ */
+ FAILURE(40),
+
+ /**
+ * 已终止
+ */
+ TERMINATED(50),
+
+ ;
+
+ private final Integer status;
+
+ public static BuildStatus of(Integer status) {
+ if (status == null) {
+ return null;
+ }
+ for (BuildStatus value : values()) {
+ if (value.status.equals(status)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/PipelineDetailStatus.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/PipelineDetailStatus.java
new file mode 100644
index 0000000..9267a6c
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/PipelineDetailStatus.java
@@ -0,0 +1,58 @@
+
+package cn.orionsec.ops.constant.app;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+
+@AllArgsConstructor
+@Getter
+public enum PipelineDetailStatus {
+
+ /**
+ * 未开始
+ */
+ WAIT(10),
+
+ /**
+ * 进行中
+ */
+ RUNNABLE(20),
+
+ /**
+ * 已完成
+ */
+ FINISH(30),
+
+ /**
+ * 执行失败
+ */
+ FAILURE(40),
+
+ /**
+ * 已跳过
+ */
+ SKIPPED(50),
+
+ /**
+ * 已终止
+ */
+ TERMINATED(60),
+
+ ;
+
+ private final Integer status;
+
+ public static PipelineDetailStatus of(Integer status) {
+ if (status == null) {
+ return null;
+ }
+ for (PipelineDetailStatus value : values()) {
+ if (value.status.equals(status)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/PipelineLogStatus.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/PipelineLogStatus.java
new file mode 100644
index 0000000..99f60f3
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/PipelineLogStatus.java
@@ -0,0 +1,84 @@
+
+package cn.orionsec.ops.constant.app;
+
+import cn.orionsec.kit.lang.utils.Strings;
+import cn.orionsec.ops.utils.Valid;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public enum PipelineLogStatus {
+
+ /**
+ * 创建
+ */
+ CREATE(10, "已创建应用 {} 构建任务 #{} ",
+ "已创建应用 {} 发布任务 #{} "),
+
+ /**
+ * 开始执行
+ */
+ EXEC(20, "开始执行应用 {} 构建任务",
+ "开始执行应用 {} 发布任务"),
+
+ /**
+ * 执行成功
+ */
+ SUCCESS(30, "应用 {} 构建任务执行成功",
+ "应用 {} 发布任务执行成功"),
+
+ /**
+ * 执行失败
+ */
+ FAILURE(40, "应用 {} 构建任务执行失败",
+ "应用 {} 发布任务执行失败"),
+
+ /**
+ * 停止执行
+ */
+ TERMINATED(50, "应用 {} 构建任务已停止执行",
+ "应用 {} 发布任务已停止执行"),
+
+ /**
+ * 跳过执行
+ */
+ SKIP(60, "应用 {} 构建任务已跳过执行",
+ "应用 {} 发布任务已跳过执行"),
+
+ ;
+
+ /**
+ * 状态
+ */
+ private final Integer status;
+
+ /**
+ * 构建模板
+ */
+ private final String buildTemplate;
+
+ /**
+ * 发布模板
+ */
+ private final String releaseTemplate;
+
+ /**
+ * 格式日志
+ *
+ * @param stage stage
+ * @param args 参数
+ * @return log
+ */
+ public String format(StageType stage, Object... args) {
+ Valid.notNull(stage);
+ if (StageType.BUILD.equals(stage)) {
+ return Strings.format(buildTemplate, args);
+ } else if (StageType.RELEASE.equals(stage)) {
+ return Strings.format(releaseTemplate, args);
+ } else {
+ return Strings.EMPTY;
+ }
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/PipelineStatus.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/PipelineStatus.java
new file mode 100644
index 0000000..9469a34
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/PipelineStatus.java
@@ -0,0 +1,68 @@
+
+package cn.orionsec.ops.constant.app;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+
+@AllArgsConstructor
+@Getter
+public enum PipelineStatus {
+
+ /**
+ * 待审核
+ */
+ WAIT_AUDIT(10),
+
+ /**
+ * 审核驳回
+ */
+ AUDIT_REJECT(20),
+
+ /**
+ * 待执行
+ */
+ WAIT_RUNNABLE(30),
+
+ /**
+ * 待调度
+ */
+ WAIT_SCHEDULE(35),
+
+ /**
+ * 执行中
+ */
+ RUNNABLE(40),
+
+ /**
+ * 执行完成
+ */
+ FINISH(50),
+
+ /**
+ * 执行停止
+ */
+ TERMINATED(60),
+
+ /**
+ * 执行失败
+ */
+ FAILURE(70),
+
+ ;
+
+ private final Integer status;
+
+ public static PipelineStatus of(Integer status) {
+ if (status == null) {
+ return null;
+ }
+ for (PipelineStatus value : values()) {
+ if (value.status.equals(status)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/ReleaseStatus.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/ReleaseStatus.java
new file mode 100644
index 0000000..ce523b5
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/ReleaseStatus.java
@@ -0,0 +1,68 @@
+
+package cn.orionsec.ops.constant.app;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+
+@AllArgsConstructor
+@Getter
+public enum ReleaseStatus {
+
+ /**
+ * 待审核
+ */
+ WAIT_AUDIT(10),
+
+ /**
+ * 审核驳回
+ */
+ AUDIT_REJECT(20),
+
+ /**
+ * 待发布
+ */
+ WAIT_RUNNABLE(30),
+
+ /**
+ * 待调度
+ */
+ WAIT_SCHEDULE(35),
+
+ /**
+ * 发布中
+ */
+ RUNNABLE(40),
+
+ /**
+ * 发布完成
+ */
+ FINISH(50),
+
+ /**
+ * 发布停止
+ */
+ TERMINATED(60),
+
+ /**
+ * 发布失败
+ */
+ FAILURE(70),
+
+ ;
+
+ private final Integer status;
+
+ public static ReleaseStatus of(Integer status) {
+ if (status == null) {
+ return null;
+ }
+ for (ReleaseStatus value : values()) {
+ if (value.status.equals(status)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/ReleaseType.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/ReleaseType.java
new file mode 100644
index 0000000..495796e
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/ReleaseType.java
@@ -0,0 +1,37 @@
+
+package cn.orionsec.ops.constant.app;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public enum ReleaseType {
+
+ /**
+ * 正常发布
+ */
+ NORMAL(10),
+
+ /**
+ * 回滚发布
+ */
+ ROLLBACK(20),
+
+ ;
+
+ private final Integer type;
+
+ public static ReleaseType of(Integer type) {
+ if (type == null) {
+ return null;
+ }
+ for (ReleaseType value : values()) {
+ if (value.type.equals(type)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/RepositoryAuthType.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/RepositoryAuthType.java
new file mode 100644
index 0000000..4d84e01
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/RepositoryAuthType.java
@@ -0,0 +1,52 @@
+
+package cn.orionsec.ops.constant.app;
+
+import cn.orionsec.ops.constant.CnConst;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public enum RepositoryAuthType {
+
+ /**
+ * 密码
+ */
+ PASSWORD(10, CnConst.PASSWORD),
+
+ /**
+ * 私人令牌
+ */
+ TOKEN(20, CnConst.TOKEN),
+
+ ;
+
+ private final Integer type;
+
+ private final String label;
+
+ public static RepositoryAuthType of(Integer type) {
+ if (type == null) {
+ return null;
+ }
+ for (RepositoryAuthType value : values()) {
+ if (value.type.equals(type)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+ public static RepositoryAuthType of(String label) {
+ if (label == null) {
+ return null;
+ }
+ for (RepositoryAuthType value : values()) {
+ if (value.label.equals(label)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/RepositoryStatus.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/RepositoryStatus.java
new file mode 100644
index 0000000..44e5e14
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/RepositoryStatus.java
@@ -0,0 +1,51 @@
+
+package cn.orionsec.ops.constant.app;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+
+@AllArgsConstructor
+@Getter
+public enum RepositoryStatus {
+
+ /**
+ * 未初始化
+ */
+ UNINITIALIZED(10),
+
+ /**
+ * 初始化中
+ */
+ INITIALIZING(20),
+
+ /**
+ * 正常
+ */
+ OK(30),
+
+ /**
+ * 失败
+ */
+ ERROR(40),
+
+ ;
+
+ /**
+ * 状态
+ */
+ private final Integer status;
+
+ public static RepositoryStatus of(Integer status) {
+ if (status == null) {
+ return null;
+ }
+ for (RepositoryStatus value : values()) {
+ if (value.status.equals(status)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/RepositoryTokenType.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/RepositoryTokenType.java
new file mode 100644
index 0000000..f305092
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/RepositoryTokenType.java
@@ -0,0 +1,64 @@
+
+package cn.orionsec.ops.constant.app;
+
+import cn.orionsec.ops.constant.Const;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+
+@AllArgsConstructor
+@Getter
+public enum RepositoryTokenType {
+
+ /**
+ * github
+ *
+ * username: ''
+ */
+ GITHUB(10, Const.GITHUB),
+
+ /**
+ * gitee
+ *
+ * username: username
+ */
+ GITEE(20, Const.GITEE),
+
+ /**
+ * gitlab
+ *
+ * username oauth
+ */
+ GITLAB(30, Const.GITLAB),
+
+ ;
+
+ private final Integer type;
+
+ private final String label;
+
+ public static RepositoryTokenType of(Integer type) {
+ if (type == null) {
+ return null;
+ }
+ for (RepositoryTokenType value : values()) {
+ if (value.type.equals(type)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+ public static RepositoryTokenType of(String label) {
+ if (label == null) {
+ return null;
+ }
+ for (RepositoryTokenType value : values()) {
+ if (value.label.equals(label.toLowerCase())) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/RepositoryType.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/RepositoryType.java
new file mode 100644
index 0000000..f32644a
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/RepositoryType.java
@@ -0,0 +1,33 @@
+
+package cn.orionsec.ops.constant.app;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+
+@AllArgsConstructor
+@Getter
+public enum RepositoryType {
+
+ /**
+ * git
+ */
+ GIT(1),
+
+ ;
+
+ private final Integer type;
+
+ public static RepositoryType of(Integer type) {
+ if (type == null) {
+ return null;
+ }
+ for (RepositoryType value : values()) {
+ if (value.type.equals(type)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/StageType.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/StageType.java
new file mode 100644
index 0000000..0798174
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/StageType.java
@@ -0,0 +1,39 @@
+
+package cn.orionsec.ops.constant.app;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public enum StageType {
+
+ /**
+ * 构建
+ */
+ BUILD(10, "构建"),
+
+ /**
+ * 发布
+ */
+ RELEASE(20, "发布"),
+
+ ;
+
+ private final Integer type;
+
+ private final String label;
+
+ public static StageType of(Integer type) {
+ if (type == null) {
+ return null;
+ }
+ for (StageType value : values()) {
+ if (value.type.equals(type)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/TimedType.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/TimedType.java
new file mode 100644
index 0000000..a41b979
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/TimedType.java
@@ -0,0 +1,38 @@
+
+package cn.orionsec.ops.constant.app;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+
+@AllArgsConstructor
+@Getter
+public enum TimedType {
+
+ /**
+ * 普通
+ */
+ NORMAL(10),
+
+ /**
+ * 定时
+ */
+ TIMED(20),
+
+ ;
+
+ private final Integer type;
+
+ public static TimedType of(Integer type) {
+ if (type == null) {
+ return null;
+ }
+ for (TimedType value : values()) {
+ if (value.type.equals(type)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/TransferFileType.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/TransferFileType.java
new file mode 100644
index 0000000..6cf5cb4
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/TransferFileType.java
@@ -0,0 +1,39 @@
+
+package cn.orionsec.ops.constant.app;
+
+import lombok.Getter;
+
+@Getter
+public enum TransferFileType {
+
+ /**
+ * 文件 / 文件夹
+ */
+ NORMAL,
+
+ /**
+ * 文件夹 zip 文件
+ */
+ ZIP,
+
+ ;
+
+ TransferFileType() {
+ this.value = name().toLowerCase();
+ }
+
+ private final String value;
+
+ public static TransferFileType of(String value) {
+ if (value == null) {
+ return NORMAL;
+ }
+ for (TransferFileType type : values()) {
+ if (type.value.equals(value)) {
+ return type;
+ }
+ }
+ return NORMAL;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/TransferMode.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/TransferMode.java
new file mode 100644
index 0000000..442eba6
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/app/TransferMode.java
@@ -0,0 +1,39 @@
+
+package cn.orionsec.ops.constant.app;
+
+import lombok.Getter;
+
+@Getter
+public enum TransferMode {
+
+ /**
+ * scp
+ */
+ SCP,
+
+ /**
+ * sftp
+ */
+ SFTP,
+
+ ;
+
+ TransferMode() {
+ this.value = name().toLowerCase();
+ }
+
+ private final String value;
+
+ public static TransferMode of(String value) {
+ if (value == null) {
+ return SCP;
+ }
+ for (TransferMode type : values()) {
+ if (type.value.equals(value)) {
+ return type;
+ }
+ }
+ return SCP;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/command/CommandConst.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/command/CommandConst.java
new file mode 100644
index 0000000..856542a
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/command/CommandConst.java
@@ -0,0 +1,24 @@
+
+package cn.orionsec.ops.constant.command;
+
+import cn.orionsec.ops.constant.env.EnvConst;
+
+
+public class CommandConst {
+
+ private CommandConst() {
+ }
+
+ public static final String TAIL_FILE_DEFAULT = "tail -f -n "
+ + EnvConst.getReplaceVariable(EnvConst.OFFSET)
+ + " '" + EnvConst.getReplaceVariable(EnvConst.FILE)
+ + "'";
+
+ public static final String SCP_TRANSFER_DEFAULT = "scp \""
+ + EnvConst.getReplaceVariable(EnvConst.BUNDLE_PATH)
+ + "\" " + EnvConst.getReplaceVariable(EnvConst.TARGET_USERNAME)
+ + "@" + EnvConst.getReplaceVariable(EnvConst.TARGET_HOST)
+ + ":\"" + EnvConst.getReplaceVariable(EnvConst.TRANSFER_PATH)
+ + "\"";
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/command/ExecStatus.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/command/ExecStatus.java
new file mode 100644
index 0000000..c99ae31
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/command/ExecStatus.java
@@ -0,0 +1,53 @@
+
+package cn.orionsec.ops.constant.command;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+
+@AllArgsConstructor
+@Getter
+public enum ExecStatus {
+
+ /**
+ * 10未开始
+ */
+ WAITING(10),
+
+ /**
+ * 20执行中
+ */
+ RUNNABLE(20),
+
+ /**
+ * 30执行完成
+ */
+ COMPLETE(30),
+
+ /**
+ * 40执行异常
+ */
+ EXCEPTION(40),
+
+ /**
+ * 50执行终止
+ */
+ TERMINATED(50),
+
+ ;
+
+ private final Integer status;
+
+ public static ExecStatus of(Integer status) {
+ if (status == null) {
+ return null;
+ }
+ for (ExecStatus value : values()) {
+ if (value.status.equals(status)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/command/ExecType.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/command/ExecType.java
new file mode 100644
index 0000000..f195aa7
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/command/ExecType.java
@@ -0,0 +1,32 @@
+
+package cn.orionsec.ops.constant.command;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public enum ExecType {
+
+ /**
+ * 批量执行
+ */
+ BATCH_EXEC(10),
+
+ ;
+
+ /**
+ * 类型
+ */
+ private final Integer type;
+
+ public static ExecType of(Integer type) {
+ for (ExecType value : values()) {
+ if (value.type.equals(type)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/common/AuditStatus.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/common/AuditStatus.java
new file mode 100644
index 0000000..1b876db
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/common/AuditStatus.java
@@ -0,0 +1,37 @@
+
+package cn.orionsec.ops.constant.common;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public enum AuditStatus {
+
+ /**
+ * 通过
+ */
+ RESOLVE(10),
+
+ /**
+ * 驳回
+ */
+ REJECT(20),
+
+ ;
+
+ private final Integer status;
+
+ public static AuditStatus of(Integer status) {
+ if (status == null) {
+ return null;
+ }
+ for (AuditStatus value : values()) {
+ if (value.status.equals(status)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/common/EnableType.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/common/EnableType.java
new file mode 100644
index 0000000..af3d4bb
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/common/EnableType.java
@@ -0,0 +1,51 @@
+
+package cn.orionsec.ops.constant.common;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum EnableType {
+
+ /**
+ * 启用
+ */
+ ENABLED(Boolean.TRUE, "enabled"),
+
+ /**
+ * 停用
+ */
+ DISABLED(Boolean.FALSE, "disabled"),
+
+ ;
+
+ private final Boolean value;
+
+ private final String label;
+
+ public static EnableType of(String label) {
+ if (label == null) {
+ return DISABLED;
+ }
+ for (EnableType value : values()) {
+ if (value.label.equals(label)) {
+ return value;
+ }
+ }
+ return DISABLED;
+ }
+
+ public static EnableType of(Boolean value) {
+ if (value == null) {
+ return DISABLED;
+ }
+ for (EnableType type : values()) {
+ if (type.value.equals(value)) {
+ return type;
+ }
+ }
+ return DISABLED;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/common/ExceptionHandlerType.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/common/ExceptionHandlerType.java
new file mode 100644
index 0000000..175f04f
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/common/ExceptionHandlerType.java
@@ -0,0 +1,52 @@
+
+package cn.orionsec.ops.constant.common;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+
+@Getter
+@AllArgsConstructor
+public enum ExceptionHandlerType {
+
+ /**
+ * 跳过所有 中断执行
+ */
+ SKIP_ALL(10, "skip_all"),
+
+ /**
+ * 跳过错误 继续执行
+ */
+ SKIP_ERROR(20, "skip_error"),
+
+ ;
+
+ private final Integer type;
+
+ private final String value;
+
+ public static ExceptionHandlerType of(Integer type) {
+ if (type == null) {
+ return ExceptionHandlerType.SKIP_ALL;
+ }
+ for (ExceptionHandlerType value : values()) {
+ if (value.type.equals(type)) {
+ return value;
+ }
+ }
+ return ExceptionHandlerType.SKIP_ALL;
+ }
+
+ public static ExceptionHandlerType of(String value) {
+ if (value == null) {
+ return ExceptionHandlerType.SKIP_ALL;
+ }
+ for (ExceptionHandlerType type : values()) {
+ if (type.value.equals(value)) {
+ return type;
+ }
+ }
+ return ExceptionHandlerType.SKIP_ALL;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/common/SerialType.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/common/SerialType.java
new file mode 100644
index 0000000..6597b78
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/common/SerialType.java
@@ -0,0 +1,50 @@
+package cn.orionsec.ops.constant.common;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public enum SerialType {
+
+ /**
+ * 串行
+ */
+ SERIAL(10, "serial"),
+
+ /**
+ * 并行
+ */
+ PARALLEL(20, "parallel"),
+
+ ;
+
+ private final Integer type;
+
+ private final String value;
+
+ public static SerialType of(Integer type) {
+ if (type == null) {
+ return PARALLEL;
+ }
+ for (SerialType value : values()) {
+ if (value.type.equals(type)) {
+ return value;
+ }
+ }
+ return PARALLEL;
+ }
+
+ public static SerialType of(String value) {
+ if (value == null) {
+ return PARALLEL;
+ }
+ for (SerialType type : values()) {
+ if (type.value.equalsIgnoreCase(value)) {
+ return type;
+ }
+ }
+ return PARALLEL;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/common/StainCode.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/common/StainCode.java
new file mode 100644
index 0000000..6786652
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/common/StainCode.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2021 - present Jiahang Li All rights reserved.
+ *
+ * https://ops.orionsec.cn
+ *
+ * Members:
+ * Jiahang Li - ljh1553488six@139.com - author
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cn.orionsec.ops.constant.common;
+
+/**
+ * ANSI 高亮颜色转义码
+ *
+ * \u001B = \x1b = 27 = esc
+ *
+ * 基本8色 基本高对比色 xterm 256 色
+ * 30 ~ 37 90 ~ 97 0 ~ 256
+ *
+ * \033[0m 关闭所有属性
+ * \033[1m 设置高亮度
+ * \033[4m 下划线
+ * \033[5m 闪烁
+ * \033[7m 反显
+ * \033[8m 消隐
+ * \033[30m 至 \33[37m 设置前景色
+ * \033[40m 至 \33[47m 设置背景色
+ * \033[nA 光标上移n行
+ * \033[nB 光标下移n行
+ * \033[nC 光标右移n行
+ * \033[nD 光标左移n行
+ * \033[y;xH 设置光标位置
+ * \033[2J 清屏
+ * \033[K 清除从光标到行尾的内容
+ * \033[s 保存光标位置
+ * \033[u 恢复光标位置
+ * \033[?25l 隐藏光标
+ * \033[?25h 显示光标
+ *
+ * @author Jiahang Li
+ * @version 1.0.0
+ * @since 2022/4/20 23:16
+ */
+public class StainCode {
+
+ private StainCode() {
+ }
+
+ /**
+ * 结束
+ * \x1b[0m
+ */
+ public static String SUFFIX = (char) 27 + "[0m";
+
+ // -------------------- 颜色 --------------------
+
+ /**
+ * 黑色
+ */
+ public static final int BLACK = 30;
+
+ /**
+ * 红色
+ */
+ public static final int RED = 31;
+
+ /**
+ * 绿色
+ */
+ public static final int GREEN = 32;
+
+ /**
+ * 黄色
+ */
+ public static final int YELLOW = 33;
+
+ /**
+ * 蓝色
+ */
+ public static final int BLUE = 34;
+
+ /**
+ * 紫色
+ */
+ public static final int PURPLE = 35;
+
+ /**
+ * 青色
+ */
+ public static final int CYAN = 36;
+
+ /**
+ * 白色
+ */
+ public static final int WHITE = 37;
+
+ // -------------------- 背景色 --------------------
+
+ /**
+ * 黑色 背景色
+ */
+ public static final int BG_BLACK = 40;
+
+ /**
+ * 红色 背景色
+ */
+ public static final int BG_RED = 41;
+
+ /**
+ * 绿色 背景色
+ */
+ public static final int BG_GREEN = 42;
+
+ /**
+ * 黄色 背景色
+ */
+ public static final int BG_YELLOW = 43;
+
+ /**
+ * 蓝色 背景色
+ */
+ public static final int BG_BLUE = 44;
+
+ /**
+ * 紫色 背景色
+ */
+ public static final int BG_PURPLE = 45;
+
+ /**
+ * 青色 背景色
+ */
+ public static final int BG_CYAN = 46;
+
+ /**
+ * 白色 背景色
+ */
+ public static final int BG_WHITE = 47;
+
+ // -------------------- 亮色 --------------------
+
+ /**
+ * 亮黑色 (灰)
+ */
+ public static final int GLOSS_BLACK = 90;
+
+ /**
+ * 亮红色
+ */
+ public static final int GLOSS_RED = 91;
+
+ /**
+ * 亮绿色
+ */
+ public static final int GLOSS_GREEN = 92;
+
+ /**
+ * 亮黄色
+ */
+ public static final int GLOSS_YELLOW = 93;
+
+ /**
+ * 亮蓝色
+ */
+ public static final int GLOSS_BLUE = 94;
+
+ /**
+ * 亮紫色
+ */
+ public static final int GLOSS_PURPLE = 95;
+
+ /**
+ * 亮青色
+ */
+ public static final int GLOSS_CYAN = 96;
+
+ /**
+ * 亮白色
+ */
+ public static final int GLOSS_WHITE = 97;
+
+ // -------------------- 亮背景色 --------------------
+
+ /**
+ * 亮黑色 (灰) 背景色
+ */
+ public static final int BG_GLOSS_BLACK = 100;
+
+ /**
+ * 亮红色 背景色
+ */
+ public static final int BG_GLOSS_RED = 101;
+
+ /**
+ * 亮绿色 背景色
+ */
+ public static final int BG_GLOSS_GREEN = 102;
+
+ /**
+ * 亮黄色 背景色
+ */
+ public static final int BG_GLOSS_YELLOW = 103;
+
+ /**
+ * 亮蓝色 背景色
+ */
+ public static final int BG_GLOSS_BLUE = 104;
+
+ /**
+ * 亮紫色 背景色
+ */
+ public static final int BG_GLOSS_PURPLE = 105;
+
+ /**
+ * 亮青色 背景色
+ */
+ public static final int BG_GLOSS_CYAN = 106;
+
+ /**
+ * 亮白色 背景色
+ */
+ public static final int BG_GLOSS_WHITE = 107;
+
+ /**
+ * 获取颜色前缀
+ * .e.g \x1b[31m
+ *
+ * @param code code
+ * @return 前缀
+ */
+ public static String prefix(int code) {
+ return (char) 27 + "[" + code + "m";
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/common/TreeMoveType.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/common/TreeMoveType.java
new file mode 100644
index 0000000..bf06194
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/common/TreeMoveType.java
@@ -0,0 +1,46 @@
+package cn.orionsec.ops.constant.common;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum TreeMoveType {
+
+ /**
+ * 移动到内层 上面
+ */
+ IN_TOP(1),
+
+ /**
+ * 移动到内层 下面
+ */
+ IN_BOTTOM(2),
+
+ /**
+ * 移动到节点 上面
+ */
+ PREV(3),
+
+ /**
+ * 移动到节点 下面
+ */
+ NEXT(4),
+
+ ;
+
+ private final Integer type;
+
+ public static TreeMoveType of(Integer type) {
+ if (type == null) {
+ return null;
+ }
+ for (TreeMoveType value : values()) {
+ if (value.type.equals(type)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/download/FileDownloadType.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/download/FileDownloadType.java
new file mode 100644
index 0000000..3c0e58f
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/download/FileDownloadType.java
@@ -0,0 +1,98 @@
+package cn.orionsec.ops.constant.download;
+
+import cn.orionsec.ops.constant.system.SystemEnvAttr;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public enum FileDownloadType {
+
+ /**
+ * 密钥
+ *
+ * @see SystemEnvAttr#KEY_PATH
+ */
+ SECRET_KEY(10),
+
+ /**
+ * terminal 录屏
+ *
+ * @see SystemEnvAttr#LOG_PATH
+ */
+ TERMINAL_SCREEN(20),
+
+ /**
+ * 命令 执行日志
+ *
+ * @see SystemEnvAttr#LOG_PATH
+ */
+ EXEC_LOG(30),
+
+ /**
+ * sftp 下载文件
+ *
+ * @see SystemEnvAttr#SWAP_PATH
+ */
+ SFTP_DOWNLOAD(40),
+
+ /**
+ * tail 列表文件
+ */
+ TAIL_LIST_FILE(50),
+
+ /**
+ * 应用构建日志
+ *
+ * @see SystemEnvAttr#LOG_PATH
+ */
+ APP_BUILD_LOG(60),
+
+ /**
+ * 应用构建操作日志
+ *
+ * @see SystemEnvAttr#LOG_PATH
+ */
+ APP_ACTION_LOG(70),
+
+ /**
+ * 应用构建 产物文件
+ *
+ * @see SystemEnvAttr#DIST_PATH
+ */
+ APP_BUILD_BUNDLE(80),
+
+ /**
+ * 应用发布 机器日志
+ *
+ * @see SystemEnvAttr#LOG_PATH
+ */
+ APP_RELEASE_MACHINE_LOG(90),
+
+ /**
+ * 调度任务机器日志
+ *
+ * @see SystemEnvAttr#LOG_PATH
+ */
+ SCHEDULER_TASK_MACHINE_LOG(110),
+
+ ;
+
+ /**
+ * 类型
+ */
+ private final Integer type;
+
+ public static FileDownloadType of(Integer type) {
+ if (type == null) {
+ return null;
+ }
+ for (FileDownloadType value : values()) {
+ if (type.equals(value.type)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/env/EnvConst.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/env/EnvConst.java
new file mode 100644
index 0000000..ef44d43
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/env/EnvConst.java
@@ -0,0 +1,99 @@
+
+package cn.orionsec.ops.constant.env;
+
+public class EnvConst {
+
+ private EnvConst() {
+ }
+
+ // -------------------- symbol --------------------
+
+ public static final String SYMBOL = "@";
+
+ // -------------------- prefix --------------------
+
+ public static final String MACHINE_PREFIX = "machine.";
+
+ public static final String APP_PREFIX = "app.";
+
+ public static final String BUILD_PREFIX = "build.";
+
+ public static final String RELEASE_PREFIX = "release.";
+
+ public static final String SYSTEM_PREFIX = "system.";
+
+ // -------------------- machine --------------------
+
+ public static final String MACHINE_ID = "machine_id";
+
+ public static final String MACHINE_NAME = "machine_name";
+
+ public static final String MACHINE_TAG = "machine_tag";
+
+ public static final String MACHINE_HOST = "machine_host";
+
+ public static final String MACHINE_PORT = "machine_port";
+
+ public static final String MACHINE_USERNAME = "machine_username";
+
+ // -------------------- app --------------------
+
+ public static final String APP_ID = "app_id";
+
+ public static final String APP_NAME = "app_name";
+
+ public static final String APP_TAG = "app_tag";
+
+ public static final String PROFILE_ID = "profile_id";
+
+ public static final String PROFILE_NAME = "profile_name";
+
+ public static final String PROFILE_TAG = "profile_tag";
+
+ // -------------------- build --------------------
+
+ public static final String BUILD_ID = "build_id";
+
+ public static final String BUILD_SEQ = "build_seq";
+
+ public static final String REPO_HOME = "repo_home";
+
+ public static final String REPO_EVENT_HOME = "repo_event_home";
+
+ public static final String BRANCH = "branch";
+
+ public static final String COMMIT = "commit";
+
+ public static final String BUNDLE_PATH = "bundle_path";
+
+ // -------------------- release --------------------
+
+ public static final String RELEASE_ID = "release_id";
+
+ public static final String RELEASE_TITLE = "release_title";
+
+ public static final String TRANSFER_PATH = "transfer_path";
+
+ // -------------------- tail --------------------
+
+ public static final String OFFSET = "offset";
+
+ public static final String FILE = "file";
+
+ // -------------------- scp --------------------
+
+ public static final String TARGET_USERNAME = "target_username";
+
+ public static final String TARGET_HOST = "target_host";
+
+ /**
+ * 获取替换变量
+ *
+ * @param name name
+ * @return command
+ */
+ public static String getReplaceVariable(String name) {
+ return SYMBOL + "{" + name + "}";
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/env/EnvViewType.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/env/EnvViewType.java
new file mode 100644
index 0000000..2323b6a
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/env/EnvViewType.java
@@ -0,0 +1,92 @@
+package cn.orionsec.ops.constant.env;
+
+import cn.orionsec.kit.lang.define.collect.MutableLinkedHashMap;
+import cn.orionsec.ops.utils.AttrConverts;
+import lombok.AllArgsConstructor;
+
+import java.util.Map;
+
+@AllArgsConstructor
+public enum EnvViewType {
+
+ /**
+ * json
+ */
+ JSON(10) {
+ @Override
+ public String toValue(Map value) {
+ return AttrConverts.toJson(value);
+ }
+
+ @Override
+ public MutableLinkedHashMap toMap(String value) {
+ return AttrConverts.fromJson(value);
+ }
+ },
+
+ /**
+ * xml
+ */
+ XML(20) {
+ @Override
+ public String toValue(Map value) {
+ return AttrConverts.toXml(value);
+ }
+
+ @Override
+ public MutableLinkedHashMap toMap(String value) {
+ return AttrConverts.fromXml(value);
+ }
+ },
+
+ /**
+ * yml
+ */
+ YML(30) {
+ @Override
+ public String toValue(Map value) {
+ return AttrConverts.toYml(value);
+ }
+
+ @Override
+ public MutableLinkedHashMap toMap(String value) {
+ return AttrConverts.fromYml(value);
+ }
+ },
+
+ /**
+ * properties
+ */
+ PROPERTIES(40) {
+ @Override
+ public String toValue(Map value) {
+ return AttrConverts.toProperties(value);
+ }
+
+ @Override
+ public MutableLinkedHashMap toMap(String value) {
+ return AttrConverts.fromProperties(value);
+ }
+ },
+
+ ;
+
+ private final Integer type;
+
+ public abstract String toValue(Map value);
+
+ public abstract MutableLinkedHashMap toMap(String value);
+
+ public static EnvViewType of(Integer type) {
+ if (type == null) {
+ return null;
+ }
+ for (EnvViewType value : values()) {
+ if (value.type.equals(type)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/event/EventClassify.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/event/EventClassify.java
new file mode 100644
index 0000000..929481d
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/event/EventClassify.java
@@ -0,0 +1,171 @@
+package cn.orionsec.ops.constant.event;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public enum EventClassify {
+
+ /**
+ * 认证操作
+ */
+ AUTHENTICATION(100, "认证操作"),
+
+ /**
+ * 用户操作
+ */
+ USER(110, "用户操作"),
+
+ /**
+ * 报警组操作
+ */
+ ALARM_GROUP(120, "报警组操作"),
+
+ /**
+ * 机器操作
+ */
+ MACHINE(200, "机器操作"),
+
+ /**
+ * 机器环境变量操作
+ */
+ MACHINE_ENV(210, "机器环境变量操作"),
+
+ /**
+ * 密钥操作
+ */
+ MACHINE_KEY(220, "密钥操作"),
+
+ /**
+ * 代理操作
+ */
+ MACHINE_PROXY(230, "代理操作"),
+
+ /**
+ * 机器监控
+ */
+ MACHINE_MONITOR(240, "机器监控"),
+
+ /**
+ * 机器报警
+ */
+ MACHINE_ALARM(250, "机器报警"),
+
+ /**
+ * 终端操作
+ */
+ TERMINAL(260, "终端操作"),
+
+ /**
+ * sftp 操作
+ */
+ SFTP(270, "sftp 操作"),
+
+ /**
+ * 批量执行操作
+ */
+ EXEC(300, "批量执行操作"),
+
+ /**
+ * 日志追踪操作
+ */
+ TAIL(310, "日志追踪操作"),
+
+ /**
+ * 调度操作
+ */
+ SCHEDULER(320, "调度操作"),
+
+ /**
+ * 应用操作
+ */
+ APP(400, "应用操作"),
+
+ /**
+ * 环境操作
+ */
+ PROFILE(410, "环境操作"),
+
+ /**
+ * 应用环境变量操作
+ */
+ APP_ENV(420, "应用环境变量操作"),
+
+ /**
+ * 应用仓库操作
+ */
+ REPOSITORY(430, "应用仓库操作"),
+
+ /**
+ * 应用构建操作
+ */
+ BUILD(440, "应用构建操作"),
+
+ /**
+ * 应用发布操作
+ */
+ RELEASE(450, "应用发布操作"),
+
+ /**
+ * 应用流水线
+ */
+ PIPELINE(460, "应用流水线"),
+
+ /**
+ * 模板操作
+ */
+ TEMPLATE(500, "模板操作"),
+
+ /**
+ * webhook 操作
+ */
+ WEBHOOK(510, "webhook操作"),
+
+ /**
+ * 系统操作
+ */
+ SYSTEM(600, "系统操作"),
+
+ /**
+ * 系统环境变量操作
+ */
+ SYSTEM_ENV(610, "系统环境变量操作"),
+
+ /**
+ * 数据清理
+ */
+ DATA_CLEAR(620, "数据清理"),
+
+ /**
+ * 数据导入
+ */
+ DATA_IMPORT(630, "数据导入"),
+
+ /**
+ * 数据导出
+ */
+ DATA_EXPORT(640, "数据导出"),
+
+ ;
+
+ /**
+ * 分类
+ */
+ private final Integer classify;
+
+ private final String label;
+
+ public static EventClassify of(Integer classify) {
+ if (classify == null) {
+ return null;
+ }
+ for (EventClassify value : values()) {
+ if (value.classify.equals(classify)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/event/EventKeys.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/event/EventKeys.java
new file mode 100644
index 0000000..9ed2203
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/event/EventKeys.java
@@ -0,0 +1,268 @@
+package cn.orionsec.ops.constant.event;
+
+public class EventKeys {
+
+ private EventKeys() {
+ }
+
+ /**
+ * 内置用户id
+ */
+ public static final String INNER_USER_ID = "_USER_ID_";
+
+ /**
+ * 内置用户名称
+ */
+ public static final String INNER_USER_NAME = "_USER_NAME_";
+
+ /**
+ * 内置是否保存
+ */
+ public static final String INNER_SAVE = "_SAVE_";
+
+ /**
+ * 内置模板
+ */
+ public static final String INNER_TEMPLATE = "_TEMPLATE_";
+
+ /**
+ * 请求序列
+ */
+ public static final String INNER_REQUEST_SEQ = "_REQUEST_SEQ_";
+
+ /**
+ * 请求 UA
+ */
+ public static final String INNER_REQUEST_USER_AGENT = "userAgent";
+
+ /**
+ * 请求 ip
+ */
+ public static final String INNER_REQUEST_IP = "ip";
+
+ /**
+ * 请求时间
+ */
+ public static final String INNER_REQUEST_TIME = "requestTime";
+
+ /**
+ * id
+ */
+ public static final String ID = "id";
+
+ /**
+ * id list
+ */
+ public static final String ID_LIST = "idList";
+
+ /**
+ * machine id
+ */
+ public static final String MACHINE_ID = "machineId";
+
+ /**
+ * machine id list
+ */
+ public static final String MACHINE_ID_LIST = "machineIdList";
+
+ /**
+ * app id
+ */
+ public static final String APP_ID = "appId";
+
+ /**
+ * profile id
+ */
+ public static final String PROFILE_ID = "profileId";
+
+ /**
+ * detail id
+ */
+ public static final String DETAIL_ID = "detailId";
+
+ /**
+ * type
+ */
+ public static final String TYPE = "type";
+
+ /**
+ * value
+ */
+ public static final String VALUE = "value";
+
+ /**
+ * token
+ */
+ public static final String TOKEN = "token";
+
+ /**
+ * 名称
+ */
+ public static final String NAME = "name";
+
+ /**
+ * 主机
+ */
+ public static final String HOST = "host";
+
+ /**
+ * 用户名
+ */
+ public static final String USERNAME = "username";
+
+ /**
+ * 源
+ */
+ public static final String SOURCE = "source";
+
+ /**
+ * 目标
+ */
+ public static final String TARGET = "target";
+
+ /**
+ * 数量
+ */
+ public static final String COUNT = "count";
+
+ /**
+ * 环境数量
+ */
+ public static final String ENV_COUNT = "envCount";
+
+ /**
+ * 机器数量
+ */
+ public static final String MACHINE_COUNT = "machineCount";
+
+ /**
+ * 机器名称
+ */
+ public static final String MACHINE_NAME = "machineName";
+
+ /**
+ * 环境数量
+ */
+ public static final String PROFILE_COUNT = "profileCount";
+
+ /**
+ * 路径
+ */
+ public static final String PATH = "path";
+
+ /**
+ * 路径
+ */
+ public static final String PATHS = "paths";
+
+ /**
+ * 操作
+ */
+ public static final String OPERATOR = "operator";
+
+ /**
+ * 序列
+ */
+ public static final String SEQ = "seq";
+
+ /**
+ * 构建序列
+ */
+ public static final String BUILD_SEQ = "buildSeq";
+
+ /**
+ * 环境名称
+ */
+ public static final String PROFILE_NAME = "profileName";
+
+ /**
+ * 应用名称
+ */
+ public static final String APP_NAME = "appName";
+
+ /**
+ * 标题
+ */
+ public static final String TITLE = "title";
+
+ /**
+ * 阶段
+ */
+ public static final String STAGE = "stage";
+
+ /**
+ * 系统
+ */
+ public static final String SYSTEM = "system";
+
+ /**
+ * before
+ */
+ public static final String BEFORE = "before";
+
+ /**
+ * after
+ */
+ public static final String AFTER = "after";
+
+ /**
+ * key
+ */
+ public static final String KEY = "key";
+
+ /**
+ * label
+ */
+ public static final String LABEL = "label";
+
+ /**
+ * time
+ */
+ public static final String TIME = "time";
+
+ /**
+ * details
+ */
+ public static final String DETAILS = "details";
+
+ /**
+ * 流水线id
+ */
+ public static final String PIPELINE_ID = "pipelineId";
+
+ /**
+ * 是否导出密码
+ */
+ public static final String EXPORT_PASSWORD = "exportPassword";
+
+ /**
+ * 保护密码
+ */
+ public static final String PROTECT = "protect";
+
+ /**
+ * 分类
+ */
+ public static final String CLASSIFY = "classify";
+
+ /**
+ * 用户id
+ */
+ public static final String USER_ID = "userId";
+
+ /**
+ * 状态
+ */
+ public static final String STATUS = "status";
+
+ /**
+ * 是否为自动续签登录
+ */
+ public static final String REFRESH_LOGIN = "refreshLogin";
+
+ /**
+ * 导出类型
+ */
+ public static final String EXPORT_TYPE = "exportType";
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/event/EventType.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/event/EventType.java
new file mode 100644
index 0000000..cdde98c
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/event/EventType.java
@@ -0,0 +1,720 @@
+package cn.orionsec.ops.constant.event;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum EventType {
+
+ // -------------------- 认证操作 --------------------
+
+ /**
+ * 登录
+ */
+ LOGIN(100010, EventClassify.AUTHENTICATION, "登录系统", "登录系统"),
+
+ /**
+ * 登出
+ */
+ LOGOUT(100020, EventClassify.AUTHENTICATION, "退出系统", "退出系统"),
+
+ /**
+ * 重置密码
+ */
+ RESET_PASSWORD(100030, EventClassify.AUTHENTICATION, "重置密码", "重置用户 ${username} 密码"),
+
+ // -------------------- 用户操作 --------------------
+
+ /**
+ * 添加用户
+ */
+ ADD_USER(110010, EventClassify.USER, "添加用户", "添加用户 ${username} "),
+
+ /**
+ * 修改用户信息
+ */
+ UPDATE_USER(110020, EventClassify.USER, "修改用户信息", "修改用户信息 ${username} "),
+
+ /**
+ * 删除用户
+ */
+ DELETE_USER(110030, EventClassify.USER, "删除用户", "删除用户 ${username} "),
+
+ /**
+ * 修改用户状态
+ */
+ CHANGE_USER_STATUS(110040, EventClassify.USER, "修改用户状态", "${operator}用户 ${username} "),
+
+ /**
+ * 解锁用户
+ */
+ UNLOCK_USER(110050, EventClassify.USER, "解锁用户", "解锁用户 ${username} "),
+
+ // -------------------- 报警组操作 --------------------
+
+ /**
+ * 添加报警组
+ */
+ ADD_ALARM_GROUP(120010, EventClassify.ALARM_GROUP, "添加报警组", "添加报警组 ${name} "),
+
+ /**
+ * 修改报警组
+ */
+ UPDATE_ALARM_GROUP(120020, EventClassify.ALARM_GROUP, "修改报警组", "修改报警组 ${before} "),
+
+ /**
+ * 删除报警组
+ */
+ DELETE_ALARM_GROUP(120030, EventClassify.ALARM_GROUP, "删除报警组", "删除报警组 ${name} "),
+
+ // -------------------- 机器操作 --------------------
+
+ /**
+ * 添加机器
+ */
+ ADD_MACHINE(200010, EventClassify.MACHINE, "添加机器", "新建机器 ${machineName} "),
+
+ /**
+ * 修改机器
+ */
+ UPDATE_MACHINE(200020, EventClassify.MACHINE, "修改机器", "修改机器 ${machineName} "),
+
+ /**
+ * 删除机器
+ */
+ DELETE_MACHINE(200030, EventClassify.MACHINE, "删除机器", "删除机器 ${count} 台"),
+
+ /**
+ * 修改机器状态
+ */
+ CHANGE_MACHINE_STATUS(200040, EventClassify.MACHINE, "修改机器状态", "${operator}机器 ${count} 台"),
+
+ /**
+ * 复制机器
+ */
+ COPY_MACHINE(200050, EventClassify.MACHINE, "复制机器", "复制机器 ${source} -> ${target} "),
+
+ // -------------------- 机器环境变量操作 --------------------
+
+ /**
+ * 删除机器环境变量
+ */
+ DELETE_MACHINE_ENV(210010, EventClassify.MACHINE_ENV, "删除机器环境变量", "删除机器环境变量 ${count} 个"),
+
+ /**
+ * 同步机器环境变量
+ */
+ SYNC_MACHINE_ENV(210020, EventClassify.MACHINE_ENV, "同步机器环境变量", "同步 ${envCount} 个环境变量 到 ${machineCount} 台机器"),
+
+ // -------------------- 密钥操作 --------------------
+
+ /**
+ * 新增密钥
+ */
+ ADD_MACHINE_KEY(220010, EventClassify.MACHINE_KEY, "新增密钥", "新建密钥 ${keyName} "),
+
+ /**
+ * 修改密钥
+ */
+ UPDATE_MACHINE_KEY(220020, EventClassify.MACHINE_KEY, "修改密钥", "修改密钥 ${name} "),
+
+ /**
+ * 删除密钥
+ */
+ DELETE_MACHINE_KEY(220030, EventClassify.MACHINE_KEY, "删除密钥", "删除密钥 ${count} 个"),
+
+ /**
+ * 绑定密钥
+ */
+ BIND_MACHINE_KEY(220040, EventClassify.MACHINE_KEY, "绑定密钥", "绑定密钥 ${name} 到${count} 台机器"),
+
+ // -------------------- 代理操作 --------------------
+
+ /**
+ * 新增代理
+ */
+ ADD_MACHINE_PROXY(230010, EventClassify.MACHINE_PROXY, "新建代理", "新建代理 ${proxyHost} "),
+
+ /**
+ * 修改代理
+ */
+ UPDATE_MACHINE_PROXY(230020, EventClassify.MACHINE_PROXY, "修改代理", "修改代理 ${host} "),
+
+ /**
+ * 删除代理
+ */
+ DELETE_MACHINE_PROXY(230030, EventClassify.MACHINE_PROXY, "删除代理", "删除代理 ${count} 个"),
+
+ // -------------------- 机器监控 --------------------
+
+ /**
+ * 修改机器监控配置
+ */
+ UPDATE_MACHINE_MONITOR_CONFIG(240010, EventClassify.MACHINE_MONITOR, "修改配置", "修改 ${name} 机器监控插件配置"),
+
+ /**
+ * 安装或升级机器监控插件
+ */
+ INSTALL_UPGRADE_MACHINE_MONITOR(240020, EventClassify.MACHINE_MONITOR, "安装/升级插件", "${operator} ${name} 机器监控插件"),
+
+ // -------------------- 报警配置 --------------------
+
+ /**
+ * 修改报警配置
+ */
+ SET_MACHINE_ALARM_CONFIG(250010, EventClassify.MACHINE_ALARM, "修改报警配置", "修改机器 ${name} ${label}报警配置"),
+
+ /**
+ * 修改报警联系组
+ */
+ SET_MACHINE_ALARM_GROUP(250020, EventClassify.MACHINE_ALARM, "修改报警联系组", "修改机器 ${name} 报警联系组"),
+
+ /**
+ * 重新发送报警通知
+ */
+ RENOTIFY_MACHINE_ALARM_GROUP(250030, EventClassify.MACHINE_ALARM, "重新发送报警通知", "重新发送机器 ${name} 报警通知"),
+
+ // -------------------- 终端操作 --------------------
+
+ /**
+ * 打开机器终端
+ */
+ OPEN_TERMINAL(260010, EventClassify.TERMINAL, "打开机器终端", "打开机器终端 ${machineName} "),
+
+ /**
+ * 强制下线终端
+ */
+ FORCE_OFFLINE_TERMINAL(260020, EventClassify.TERMINAL, "强制下线终端", "强制下线终端 ${username} ${name} "),
+
+ /**
+ * 修改终端配置
+ */
+ UPDATE_TERMINAL_CONFIG(260030, EventClassify.TERMINAL, "修改终端配置", "修改机器终端配置 ${name} "),
+
+ /**
+ * 删除终端日志
+ */
+ DELETE_TERMINAL_LOG(260040, EventClassify.TERMINAL, "删除终端日志", "删除终端操作日志 ${count} 个"),
+
+ // -------------------- sftp 操作 --------------------
+
+ /**
+ * 打开机器 SFTP
+ */
+ OPEN_SFTP(270010, EventClassify.SFTP, "打开机器 SFTP", "打开机器 SFTP ${machineName} "),
+
+ /**
+ * 创建文件夹
+ */
+ SFTP_MKDIR(270020, EventClassify.SFTP, "创建文件夹", "创建文件夹 ${path} "),
+
+ /**
+ * 创建文件
+ */
+ SFTP_TOUCH(270030, EventClassify.SFTP, "创建文件", "创建文件 ${path} "),
+
+ /**
+ * 截断文件
+ */
+ SFTP_TRUNCATE(270040, EventClassify.SFTP, "截断文件", "截断文件 ${path} "),
+
+ /**
+ * 移动文件
+ */
+ SFTP_MOVE(270050, EventClassify.SFTP, "移动文件", "移动文件 ${source} -> ${target} "),
+
+ /**
+ * 删除文件
+ */
+ SFTP_REMOVE(270060, EventClassify.SFTP, "删除文件", "删除文件 ${count} 个"),
+
+ /**
+ * 修改文件权限
+ */
+ SFTP_CHMOD(270070, EventClassify.SFTP, "修改文件权限", "修改文件权限 ${path} >>> ${permission} "),
+
+ /**
+ * 修改文件所有者
+ */
+ SFTP_CHOWN(270080, EventClassify.SFTP, "修改文件所有者", "修改文件所有者 ${path} >>> ${uid} "),
+
+ /**
+ * 修改文件所有组
+ */
+ SFTP_CHGRP(270090, EventClassify.SFTP, "修改文件所有组", "修改文件所有组 ${path} >>> ${gid} "),
+
+ /**
+ * 上传文件
+ */
+ SFTP_UPLOAD(270100, EventClassify.SFTP, "上传文件", "上传 ${count} 个文件"),
+
+ /**
+ * 下载文件
+ */
+ SFTP_DOWNLOAD(270110, EventClassify.SFTP, "下载文件", "下载 ${count} 个文件"),
+
+ /**
+ * 打包文件
+ */
+ SFTP_PACKAGE(270120, EventClassify.SFTP, "打包文件", "打包 ${count} 个文件"),
+
+ // -------------------- 批量执行操作 --------------------
+
+ /**
+ * 批量执行
+ */
+ EXEC_SUBMIT(300010, EventClassify.EXEC, "批量执行", "批量执行机器命令 ${count} 台"),
+
+ /**
+ * 删除执行
+ */
+ EXEC_DELETE(300020, EventClassify.EXEC, "删除执行", "删除机器执行命令记录 ${count} 个"),
+
+ /**
+ * 终止执行
+ */
+ EXEC_TERMINATE(300030, EventClassify.EXEC, "终止执行", "终止执行机器命令"),
+
+ // -------------------- 日志操作 --------------------
+
+ /**
+ * 添加日志文件
+ */
+ ADD_TAIL_FILE(310010, EventClassify.TAIL, "添加日志文件", "添加日志文件 ${aliasName} "),
+
+ /**
+ * 修改日志文件
+ */
+ UPDATE_TAIL_FILE(310020, EventClassify.TAIL, "修改日志文件", "修改日志文件 ${name} "),
+
+ /**
+ * 删除日志文件
+ */
+ DELETE_TAIL_FILE(310030, EventClassify.TAIL, "删除日志文件", "删除日志文件 ${count} 个"),
+
+ /**
+ * 上传日志文件
+ */
+ UPLOAD_TAIL_FILE(310040, EventClassify.TAIL, "上传日志文件", "上传日志文件 ${count} 个"),
+
+ // -------------------- 调度操作 --------------------
+
+ /**
+ * 添加调度任务
+ */
+ ADD_SCHEDULER_TASK(320010, EventClassify.SCHEDULER, "添加调度任务", "添加调度任务 ${taskName} "),
+
+ /**
+ * 修改调度任务
+ */
+ UPDATE_SCHEDULER_TASK(320020, EventClassify.SCHEDULER, "修改调度任务", "修改调度任务 ${name} "),
+
+ /**
+ * 更新调度任务状态
+ */
+ UPDATE_SCHEDULER_TASK_STATUS(320030, EventClassify.SCHEDULER, "更新任务状态", "${operator}调度任务 ${name} "),
+
+ /**
+ * 删除调度任务
+ */
+ DELETE_SCHEDULER_TASK(320040, EventClassify.SCHEDULER, "删除调度任务", "删除调度任务 ${name} "),
+
+ /**
+ * 手动触发调度任务
+ */
+ MANUAL_TRIGGER_SCHEDULER_TASK(320050, EventClassify.SCHEDULER, "手动触发任务", "手动触发调度任务 ${name} "),
+
+ /**
+ * 停止调度任务
+ */
+ TERMINATE_ALL_SCHEDULER_TASK(320060, EventClassify.SCHEDULER, "停止任务", "停止调度任务 ${name} "),
+
+ /**
+ * 停止调度任务机器操作
+ */
+ TERMINATE_SCHEDULER_TASK_MACHINE(320070, EventClassify.SCHEDULER, "停止机器操作", "停止调度任务机器操作 ${name} ${machineName} "),
+
+ /**
+ * 跳过调度任务机器操作
+ */
+ SKIP_SCHEDULER_TASK_MACHINE(320080, EventClassify.SCHEDULER, "跳过机器操作", "跳过调度任务机器操作 ${name} ${machineName} "),
+
+ /**
+ * 删除任务调度明细
+ */
+ DELETE_TASK_RECORD(320090, EventClassify.SCHEDULER, "删除调度明细", "删除调度任务明细 ${count} 个"),
+
+ // -------------------- 应用操作 --------------------
+
+ /**
+ * 添加应用
+ */
+ ADD_APP(400010, EventClassify.APP, "添加应用", "添加应用 ${appName} "),
+
+ /**
+ * 修改应用
+ */
+ UPDATE_APP(400020, EventClassify.APP, "修改应用", "修改应用 ${name} "),
+
+ /**
+ * 删除应用
+ */
+ DELETE_APP(400030, EventClassify.APP, "删除应用", "删除应用 ${name} "),
+
+ /**
+ * 配置应用
+ */
+ CONFIG_APP(400040, EventClassify.APP, "配置应用", "配置应用 ${profileName} ${appName} "),
+
+ /**
+ * 同步应用
+ */
+ SYNC_APP(400050, EventClassify.APP, "同步应用", "同步应用 ${name} 到 ${count} 个环境"),
+
+ /**
+ * 复制应用
+ */
+ COPY_APP(400060, EventClassify.APP, "复制应用", "复制应用 ${name} "),
+
+ // -------------------- 环境操作 --------------------
+
+ /**
+ * 添加应用环境
+ */
+ ADD_PROFILE(410010, EventClassify.PROFILE, "添加应用环境", "添加应用环境 ${profileName} "),
+
+ /**
+ * 修改应用环境
+ */
+ UPDATE_PROFILE(410020, EventClassify.PROFILE, "修改应用环境", "修改应用环境 ${name} "),
+
+ /**
+ * 删除应用环境
+ */
+ DELETE_PROFILE(410030, EventClassify.PROFILE, "删除应用环境", "删除应用环境 ${name} "),
+
+ // -------------------- 应用环境变量操作 --------------------
+
+ /**
+ * 删除应用环境变量
+ */
+ DELETE_APP_ENV(420010, EventClassify.APP_ENV, "删除应用环境变量", "删除应用环境变量 ${count} 个"),
+
+ /**
+ * 同步应用环境变量
+ */
+ SYNC_APP_ENV(420020, EventClassify.APP_ENV, "同步应用环境变量", "同步 ${envCount} 个环境变量 到 ${profileCount} 个环境"),
+
+ // -------------------- 版本仓库操作 --------------------
+
+ /**
+ * 添加版本仓库
+ */
+ ADD_REPOSITORY(430010, EventClassify.REPOSITORY, "添加版本仓库", "添加版本仓库 ${repoName} "),
+
+ /**
+ * 初始化版本仓库
+ */
+ INIT_REPOSITORY(430020, EventClassify.REPOSITORY, "初始化版本仓库", "初始化版本仓库 ${name} "),
+
+ /**
+ * 重新初始化版本仓库
+ */
+ RE_INIT_REPOSITORY(430030, EventClassify.REPOSITORY, "重新初始化版本仓库", "重新初始化版本仓库 ${name} "),
+
+ /**
+ * 更新版本仓库
+ */
+ UPDATE_REPOSITORY(430040, EventClassify.REPOSITORY, "更新版本仓库", "更新版本仓库 ${name} "),
+
+ /**
+ * 删除版本仓库
+ */
+ DELETE_REPOSITORY(430050, EventClassify.REPOSITORY, "删除版本仓库", "删除版本仓库 ${name} "),
+
+ /**
+ * 清空版本仓库
+ */
+ CLEAN_REPOSITORY(430060, EventClassify.REPOSITORY, "清空版本仓库", "清空版本仓库 ${name} "),
+
+ // -------------------- 构建操作 --------------------
+
+ /**
+ * 提交应用构建
+ */
+ SUBMIT_BUILD(440010, EventClassify.BUILD, "提交应用构建", "提交应用构建 #${buildSeq} ${profileName} ${appName} "),
+
+ /**
+ * 停止应用构建
+ */
+ BUILD_TERMINATE(440020, EventClassify.BUILD, "停止应用构建", "停止应用构建 #${buildSeq} ${profileName} ${appName} "),
+
+ /**
+ * 删除应用构建
+ */
+ DELETE_BUILD(440030, EventClassify.BUILD, "删除应用构建", "删除应用构建记录 ${count} 个"),
+
+ /**
+ * 重新构建应用
+ */
+ SUBMIT_REBUILD(440040, EventClassify.BUILD, "重新构建应用", "重新构建应用 #${buildSeq} ${profileName} ${appName} "),
+
+ // -------------------- 发布操作 --------------------
+
+ /**
+ * 提交应用发布
+ */
+ SUBMIT_RELEASE(450010, EventClassify.RELEASE, "提交应用发布", "提交应用发布 ${releaseTitle} "),
+
+ /**
+ * 应用发布审核
+ */
+ AUDIT_RELEASE(450020, EventClassify.RELEASE, "应用发布审核", "应用发布审核${operator} ${title} "),
+
+ /**
+ * 执行应用发布
+ */
+ RUNNABLE_RELEASE(450030, EventClassify.RELEASE, "执行应用发布", "执行应用发布 ${title} "),
+
+ /**
+ * 应用回滚发布
+ */
+ ROLLBACK_RELEASE(450040, EventClassify.RELEASE, "应用回滚发布", "应用回滚发布 ${title} "),
+
+ /**
+ * 停止应用发布
+ */
+ TERMINATE_RELEASE(450050, EventClassify.RELEASE, "停止应用发布", "停止应用发布 ${title} "),
+
+ /**
+ * 删除应用发布
+ */
+ DELETE_RELEASE(450060, EventClassify.RELEASE, "删除应用发布", "删除应用发布记录 ${count} 个"),
+
+ /**
+ * 复制应用发布
+ */
+ COPY_RELEASE(450070, EventClassify.RELEASE, "复制应用发布", "复制应用发布 ${releaseTitle} "),
+
+ /**
+ * 取消应用定时发布
+ */
+ CANCEL_TIMED_RELEASE(450080, EventClassify.RELEASE, "取消定时发布", "取消应用定时发布 ${title} "),
+
+ /**
+ * 设置应用定时发布
+ */
+ SET_TIMED_RELEASE(450090, EventClassify.RELEASE, "设置定时发布", "设置应用定时发布 ${title} -> ${time} "),
+
+ /**
+ * 停止机器发布操作
+ */
+ TERMINATE_MACHINE_RELEASE(450100, EventClassify.RELEASE, "停止机器操作", "停止机器发布操作 ${title} ${machineName} "),
+
+ /**
+ * 跳过机器发布操作
+ */
+ SKIP_MACHINE_RELEASE(450110, EventClassify.RELEASE, "跳过机器操作", "跳过机器发布操作 ${title} ${machineName} "),
+
+ // -------------------- 应用流水线 --------------------
+
+ /**
+ * 添加应用流水线
+ */
+ ADD_PIPELINE(460010, EventClassify.PIPELINE, "添加流水线", "添加应用流水线 ${pipelineName} "),
+
+ /**
+ * 修改应用流水线
+ */
+ UPDATE_PIPELINE(460020, EventClassify.PIPELINE, "修改流水线", "修改应用流水线 ${pipelineName} "),
+
+ /**
+ * 删除应用流水线
+ */
+ DELETE_PIPELINE(460030, EventClassify.PIPELINE, "删除流水线", "删除应用流水线 ${count} 个"),
+
+ /**
+ * 提交应用流水线任务
+ */
+ SUBMIT_PIPELINE_TASK(460040, EventClassify.PIPELINE, "提交执行任务", "提交应用流水线任务 ${pipelineName} ${execTitle} "),
+
+ /**
+ * 审核应用流水线任务
+ */
+ AUDIT_PIPELINE_TASK(460050, EventClassify.PIPELINE, "审核任务", "审核应用流水线任务${operator} ${name} ${title} "),
+
+ /**
+ * 复制应用流水线任务
+ */
+ COPY_PIPELINE_TASK(460060, EventClassify.PIPELINE, "复制任务", "复制应用流水线任务 ${pipelineName} ${execTitle} "),
+
+ /**
+ * 执行应用流水线任务
+ */
+ EXEC_PIPELINE_TASK(460070, EventClassify.PIPELINE, "执行任务", "执行应用流水线任务 ${name} ${title} "),
+
+ /**
+ * 删除应用流水线任务
+ */
+ DELETE_PIPELINE_TASK(460080, EventClassify.PIPELINE, "删除任务", "删除应用流水线任务 ${count} 个"),
+
+ /**
+ * 设置定时执行应用流水线任务
+ */
+ SET_PIPELINE_TIMED_TASK(460090, EventClassify.PIPELINE, "设置定时执行", "设置定时执行应用流水线任务 ${name} ${title} -> ${time} "),
+
+ /**
+ * 取消定时执行应用流水线任务
+ */
+ CANCEL_PIPELINE_TIMED_TASK(460100, EventClassify.PIPELINE, "取消定时执行", "取消定时执行应用流水线任务 ${name} ${title} "),
+
+ /**
+ * 停止执行应用流水线任务
+ */
+ TERMINATE_PIPELINE_TASK(460110, EventClassify.PIPELINE, "停止执行任务", "停止执行应用流水线任务 ${name} ${title} "),
+
+ /**
+ * 停止执行应用流水线任务操作
+ */
+ TERMINATE_PIPELINE_TASK_DETAIL(460120, EventClassify.PIPELINE, "停止执行操作", "停止执行应用流水线任务部分操作 ${name} ${title} (${stage} ${appName} )"),
+
+ /**
+ * 跳过执行应用流水线任务操作
+ */
+ SKIP_PIPELINE_TASK_DETAIL(460130, EventClassify.PIPELINE, "跳过执行操作", "跳过执行应用流水线任务部分操作 ${name} ${title} (${stage} ${appName} )"),
+
+ // -------------------- 模板操作 --------------------
+
+ /**
+ * 添加模板
+ */
+ ADD_TEMPLATE(500010, EventClassify.TEMPLATE, "添加模板", "添加模板 ${templateName} "),
+
+ /**
+ * 修改模板
+ */
+ UPDATE_TEMPLATE(500020, EventClassify.TEMPLATE, "修改模板", "修改模板 ${name} "),
+
+ /**
+ * 删除模板
+ */
+ DELETE_TEMPLATE(500030, EventClassify.TEMPLATE, "删除模板", "删除模板 ${count} 个"),
+
+ // -------------------- webhook 操作 --------------------
+
+ /**
+ * 添加 webhook 配置
+ */
+ ADD_WEBHOOK(510010, EventClassify.WEBHOOK, "添加配置", "添加 webhook ${webhookName} "),
+
+ /**
+ * 修改 webhook 配置
+ */
+ UPDATE_WEBHOOK(510020, EventClassify.WEBHOOK, "修改配置", "修改 webhook ${name} "),
+
+ /**
+ * 删除 webhook 配置
+ */
+ DELETE_WEBHOOK(510030, EventClassify.WEBHOOK, "删除配置", "删除 webhook ${name} 个"),
+
+ // -------------------- 系统操作 --------------------
+
+ /**
+ * 配置 ip 过滤器
+ */
+ CONFIG_IP_LIST(600010, EventClassify.SYSTEM, "配置IP过滤器", "配置 IP 过滤器"),
+
+ /**
+ * 重新进行系统统计分析
+ */
+ RE_ANALYSIS_SYSTEM(600020, EventClassify.SYSTEM, "系统统计分析", "重新进行系统统计分析"),
+
+ /**
+ * 清理系统文件
+ */
+ CLEAN_SYSTEM_FILE(600030, EventClassify.SYSTEM, "清理系统文件", "清理系统 ${label} "),
+
+ /**
+ * 修改系统配置
+ */
+ UPDATE_SYSTEM_OPTION(600040, EventClassify.SYSTEM, "修改系统配置", "修改系统配置项 ${label} 原始值:${before} 新值:${after} "),
+
+ // -------------------- 系统环境变量操作 --------------------
+
+ /**
+ * 添加系统环境变量
+ */
+ ADD_SYSTEM_ENV(610010, EventClassify.SYSTEM_ENV, "添加系统环境变量", "添加系统环境变量 ${attrKey} "),
+
+ /**
+ * 修改系统环境变量
+ */
+ UPDATE_SYSTEM_ENV(610020, EventClassify.SYSTEM_ENV, "修改系统环境变量", "修改系统环境变量 ${attrKey} "),
+
+ /**
+ * 删除系统环境变量
+ */
+ DELETE_SYSTEM_ENV(610030, EventClassify.SYSTEM_ENV, "删除系统环境变量", "删除系统环境变量 ${count} 个"),
+
+ /**
+ * 保存系统环境变量
+ */
+ SAVE_SYSTEM_ENV(610040, EventClassify.SYSTEM_ENV, "保存系统环境变量", "保存系统环境变量 ${count} 个"),
+
+ // -------------------- 数据清理 --------------------
+
+ /**
+ * 清理数据
+ */
+ DATA_CLEAR(620010, EventClassify.DATA_CLEAR, "清理数据", "清理数据 ${label} ${count} 条"),
+
+ // -------------------- 数据导入 --------------------
+
+ /**
+ * 导入数据
+ */
+ DATA_IMPORT(630010, EventClassify.DATA_IMPORT, "导入数据", "批量导入 ${label} "),
+
+ // -------------------- 数据导出 --------------------
+
+ /**
+ * 导出数据
+ */
+ DATA_EXPORT(640010, EventClassify.DATA_EXPORT, "导出数据", "导出 ${label} ${count} 条"),
+
+ ;
+
+ /**
+ * 类型
+ */
+ private final Integer type;
+
+ /**
+ * 分类
+ */
+ private final EventClassify classify;
+
+ /**
+ * label
+ */
+ private final String label;
+
+ /**
+ * 模板
+ */
+ private final String template;
+
+ public static EventType of(Integer type) {
+ if (type == null) {
+ return null;
+ }
+ for (EventType value : values()) {
+ if (value.type.equals(type)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/history/HistoryOperator.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/history/HistoryOperator.java
new file mode 100644
index 0000000..97e5da4
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/history/HistoryOperator.java
@@ -0,0 +1,41 @@
+package cn.orionsec.ops.constant.history;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum HistoryOperator {
+
+ /**
+ * 添加
+ */
+ ADD(1),
+
+ /**
+ * 更新
+ */
+ UPDATE(2),
+
+ /**
+ * 删除
+ */
+ DELETE(3),
+
+ ;
+
+ private final Integer type;
+
+ public static HistoryOperator of(Integer type) {
+ if (type == null) {
+ return null;
+ }
+ for (HistoryOperator value : values()) {
+ if (value.type.equals(type)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/history/HistoryValueType.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/history/HistoryValueType.java
new file mode 100644
index 0000000..8a3d880
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/history/HistoryValueType.java
@@ -0,0 +1,41 @@
+package cn.orionsec.ops.constant.history;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public enum HistoryValueType {
+
+ /**
+ * 机器环境变量
+ */
+ MACHINE_ENV(10),
+
+ /**
+ * 应用环境变量
+ */
+ APP_ENV(20),
+
+ /**
+ * 系统环境变量
+ */
+ SYSTEM_ENV(30),
+
+ ;
+
+ private final Integer type;
+
+ public static HistoryValueType of(Integer type) {
+ if (type == null) {
+ return null;
+ }
+ for (HistoryValueType value : values()) {
+ if (type.equals(value.type)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/machine/MachineAlarmType.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/machine/MachineAlarmType.java
new file mode 100644
index 0000000..ef16e57
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/machine/MachineAlarmType.java
@@ -0,0 +1,38 @@
+package cn.orionsec.ops.constant.machine;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum MachineAlarmType {
+
+ /**
+ * cpu 使用率
+ */
+ CPU_USAGE(10, "CPU使用率"),
+
+ /**
+ * 内存使用率
+ */
+ MEMORY_USAGE(20, "内存使用率"),
+
+ ;
+
+ private final Integer type;
+
+ private final String label;
+
+ public static MachineAlarmType of(Integer type) {
+ if (type == null) {
+ return null;
+ }
+ for (MachineAlarmType value : values()) {
+ if (value.type.equals(type)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/machine/MachineAuthType.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/machine/MachineAuthType.java
new file mode 100644
index 0000000..e670555
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/machine/MachineAuthType.java
@@ -0,0 +1,51 @@
+package cn.orionsec.ops.constant.machine;
+
+import cn.orionsec.ops.constant.CnConst;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum MachineAuthType {
+
+ /**
+ * 1 密码认证
+ */
+ PASSWORD(1, CnConst.PASSWORD),
+
+ /**
+ * 2 独立密钥
+ */
+ SECRET_KEY(2, CnConst.SECRET_KEY),
+
+ ;
+
+ private final Integer type;
+
+ private final String label;
+
+ public static MachineAuthType of(Integer type) {
+ if (type == null) {
+ return null;
+ }
+ for (MachineAuthType value : values()) {
+ if (value.type.equals(type)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+ public static MachineAuthType of(String label) {
+ if (label == null) {
+ return null;
+ }
+ for (MachineAuthType value : values()) {
+ if (value.label.equals(label)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/machine/MachineConst.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/machine/MachineConst.java
new file mode 100644
index 0000000..5e8424b
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/machine/MachineConst.java
@@ -0,0 +1,20 @@
+package cn.orionsec.ops.constant.machine;
+
+import cn.orionsec.ops.constant.Const;
+
+public class MachineConst {
+
+ private MachineConst() {
+ }
+
+ /**
+ * 远程连接尝试次数
+ */
+ public static final int CONNECT_RETRY_TIMES = 1;
+
+ /**
+ * 远程连接超时时间
+ */
+ public static final int CONNECT_TIMEOUT = Const.MS_S_30;
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/machine/MachineEnvAttr.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/machine/MachineEnvAttr.java
new file mode 100644
index 0000000..c8b845f
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/machine/MachineEnvAttr.java
@@ -0,0 +1,89 @@
+package cn.orionsec.ops.constant.machine;
+
+import cn.orionsec.ops.constant.Const;
+import cn.orionsec.ops.constant.command.CommandConst;
+import lombok.Getter;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Getter
+public enum MachineEnvAttr {
+
+ /**
+ * sftp 文件名称编码格式
+ *
+ * @see Const#UTF_8
+ */
+ SFTP_CHARSET("SFTP 文件名称编码格式"),
+
+ /**
+ * 文件追踪偏移量
+ *
+ * @see Const#TAIL_OFFSET_LINE
+ */
+ TAIL_OFFSET("文件追踪偏移量(行)"),
+
+ /**
+ * 文件追踪编码格式
+ *
+ * @see Const#UTF_8
+ */
+ TAIL_CHARSET("文件追踪编码格式"),
+
+ /**
+ * 文件追踪默认命令
+ *
+ * @see CommandConst#TAIL_FILE_DEFAULT
+ */
+ TAIL_DEFAULT_COMMAND("文件追踪默认命令"),
+
+ /**
+ * 连接超时时间 (ms)
+ *
+ * @see MachineConst#CONNECT_TIMEOUT
+ */
+ CONNECT_TIMEOUT("连接超时时间 (ms)"),
+
+ /**
+ * 连接失败重试次数
+ *
+ * @see MachineConst#CONNECT_RETRY_TIMES
+ */
+ CONNECT_RETRY_TIMES("连接失败重试次数"),
+
+ ;
+
+ /**
+ * key
+ */
+ private final String key;
+
+ /**
+ * 描述
+ */
+ private final String description;
+
+ MachineEnvAttr(String description) {
+ this.description = description;
+ this.key = this.name().toLowerCase();
+ }
+
+ public static List getKeys() {
+ return Arrays.stream(values())
+ .map(MachineEnvAttr::getKey)
+ .collect(Collectors.toList());
+ }
+
+ public static MachineEnvAttr of(String key) {
+ if (key == null) {
+ return null;
+ }
+ return Arrays.stream(values())
+ .filter(a -> a.key.equals(key))
+ .findFirst()
+ .orElse(null);
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/machine/ProxyType.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/machine/ProxyType.java
new file mode 100644
index 0000000..d96df1e
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/machine/ProxyType.java
@@ -0,0 +1,56 @@
+package cn.orionsec.ops.constant.machine;
+
+import cn.orionsec.ops.constant.Const;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public enum ProxyType {
+
+ /**
+ * HTTP 代理
+ */
+ HTTP(1, Const.PROTOCOL_HTTP),
+
+ /**
+ * SOCKS4 代理
+ */
+ SOCKS4(2, Const.SOCKS4),
+
+ /**
+ * SOCKS5 代理
+ */
+ SOCKS5(3, Const.SOCKS5),
+
+ ;
+
+ private final Integer type;
+
+ private final String label;
+
+ public static ProxyType of(Integer type) {
+ if (type == null) {
+ return null;
+ }
+ for (ProxyType value : values()) {
+ if (value.type.equals(type)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+ public static ProxyType of(String label) {
+ if (label == null) {
+ return null;
+ }
+ for (ProxyType value : values()) {
+ if (value.label.equals(label)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/message/MessageClassify.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/message/MessageClassify.java
new file mode 100644
index 0000000..8d18d9e
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/message/MessageClassify.java
@@ -0,0 +1,43 @@
+package cn.orionsec.ops.constant.message;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public enum MessageClassify {
+
+ /**
+ * 系统消息
+ */
+ SYSTEM(10, "系统消息"),
+
+ /**
+ * 数据导入
+ */
+ IMPORT(20, "数据导入"),
+
+ /**
+ * 系统报警
+ */
+ ALARM(30, "系统报警"),
+
+ ;
+
+ private final Integer classify;
+
+ private final String label;
+
+ public static MessageClassify of(Integer classify) {
+ if (classify == null) {
+ return null;
+ }
+ for (MessageClassify value : values()) {
+ if (value.classify.equals(classify)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/message/MessageType.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/message/MessageType.java
new file mode 100644
index 0000000..ce27bb0
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/message/MessageType.java
@@ -0,0 +1,133 @@
+package cn.orionsec.ops.constant.message;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public enum MessageType {
+
+ // -------------------- 系统消息 --------------------
+
+ /**
+ * 命令执行完成
+ */
+ EXEC_SUCCESS(1010, "命令执行完成", MessageClassify.SYSTEM, "机器 ${name} 命令执行完成"),
+
+ /**
+ * 命令执行失败
+ */
+ EXEC_FAILURE(1020, "命令执行失败", MessageClassify.SYSTEM, "机器 ${name} 命令执行失败"),
+
+ /**
+ * 版本仓库初始化成功
+ */
+ REPOSITORY_INIT_SUCCESS(1030, "版本仓库初始化成功", MessageClassify.SYSTEM, "仓库 ${name} 初始化成功"),
+
+ /**
+ * 版本仓库初始化失败
+ */
+ REPOSITORY_INIT_FAILURE(1040, "版本仓库初始化失败", MessageClassify.SYSTEM, "仓库 ${name} 初始化失败"),
+
+ /**
+ * 构建执行成功
+ */
+ BUILD_SUCCESS(1050, "构建执行成功", MessageClassify.SYSTEM, "${appName} #${seq} 构建成功"),
+
+ /**
+ * 构建执行失败
+ */
+ BUILD_FAILURE(1060, "构建执行失败", MessageClassify.SYSTEM, "${appName} #${seq} 构建失败"),
+
+ /**
+ * 发布审批通过
+ */
+ RELEASE_AUDIT_RESOLVE(1070, "发布审批通过", MessageClassify.SYSTEM, "发布任务 ${title} 审核已通过"),
+
+ /**
+ * 发布审批驳回
+ */
+ RELEASE_AUDIT_REJECT(1080, "发布审批驳回", MessageClassify.SYSTEM, "发布任务 ${title} 审核已被驳回"),
+
+ /**
+ * 发布执行成功
+ */
+ RELEASE_SUCCESS(1090, "发布执行成功", MessageClassify.SYSTEM, "发布任务 ${title} 发布成功"),
+
+ /**
+ * 发布执行失败
+ */
+ RELEASE_FAILURE(1100, "发布执行失败", MessageClassify.SYSTEM, "发布任务 ${title} 发布失败"),
+
+ /**
+ * 应用流水线审批通过
+ */
+ PIPELINE_AUDIT_RESOLVE(1110, "应用流水线审批通过", MessageClassify.SYSTEM, "应用流水线 ${name} ${title} 审核已通过"),
+
+ /**
+ * 应用流水线审批驳回
+ */
+ PIPELINE_AUDIT_REJECT(1120, "应用流水线审批驳回", MessageClassify.SYSTEM, "应用流水线 ${name} ${title} 审核已被驳回"),
+
+ /**
+ * 应用流水线执行成功
+ */
+ PIPELINE_EXEC_SUCCESS(1130, "应用流水线执行成功", MessageClassify.SYSTEM, "应用流水线 ${name} ${title} 执行成功"),
+
+ /**
+ * 应用流水线执行失败
+ */
+ PIPELINE_EXEC_FAILURE(1140, "应用流水线执行失败", MessageClassify.SYSTEM, "应用流水线 ${name} ${title} 执行失败"),
+
+ /**
+ * 机器监控插件安装成功
+ */
+ MACHINE_AGENT_INSTALL_SUCCESS(1150, "机器监控插件安装成功", MessageClassify.SYSTEM, "机器 ${name} 监控插件安装成功"),
+
+ /**
+ * 机器监控插件安装失败
+ */
+ MACHINE_AGENT_INSTALL_FAILURE(1160, "机器监控插件安装失败", MessageClassify.SYSTEM, "机器 ${name} 监控插件安装失败, 请手动安装或检查插件配置"),
+
+ // -------------------- 数据导入 --------------------
+
+ /**
+ * 数据导入成功
+ */
+ DATA_IMPORT_SUCCESS(2010, "数据导入成功", MessageClassify.IMPORT, "您在 ${time} 进行的${label} 导入操作执行完成"),
+
+ /**
+ * 数据导入失败
+ */
+ DATA_IMPORT_FAILURE(2020, "数据导入失败", MessageClassify.IMPORT, "您在 ${time} 进行的${label} 导入操作执行失败"),
+
+ // -------------------- 系统报警 --------------------
+
+ /**
+ * 机器发生报警
+ */
+ MACHINE_ALARM(3010, "机器发生报警", MessageClassify.ALARM, "机器 ${name} (${host} ) ${time} ${type} 达到${value}% , 请及时排查!"),
+
+ ;
+
+ private final Integer type;
+
+ private final String label;
+
+ private final MessageClassify classify;
+
+ private final String template;
+
+ public static MessageType of(Integer type) {
+ if (type == null) {
+ return null;
+ }
+ for (MessageType value : values()) {
+ if (value.type.equals(type)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/message/ReadStatus.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/message/ReadStatus.java
new file mode 100644
index 0000000..1749a41
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/message/ReadStatus.java
@@ -0,0 +1,39 @@
+package cn.orionsec.ops.constant.message;
+
+import cn.orionsec.ops.constant.CnConst;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public enum ReadStatus {
+
+ /**
+ * 未读
+ */
+ UNREAD(1, CnConst.UNREAD),
+
+ /**
+ * 已读
+ */
+ READ(2, CnConst.READ),
+
+ ;
+
+ private final Integer status;
+
+ private final String label;
+
+ public static ReadStatus of(Integer status) {
+ if (status == null) {
+ return null;
+ }
+ for (ReadStatus value : values()) {
+ if (value.status.equals(status)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/monitor/MonitorConst.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/monitor/MonitorConst.java
new file mode 100644
index 0000000..a385221
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/monitor/MonitorConst.java
@@ -0,0 +1,86 @@
+package cn.orionsec.ops.constant.monitor;
+
+import cn.orionsec.ops.constant.Const;
+import cn.orionsec.ops.constant.PropertiesConst;
+import cn.orionsec.ops.utils.ResourceLoader;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+@Component
+public class MonitorConst {
+
+ private MonitorConst() {
+ }
+
+ /**
+ * 最新版本
+ */
+ public static String LATEST_VERSION;
+
+ /**
+ * 默认 url
+ */
+ public static String DEFAULT_URL_FORMAT;
+
+ /**
+ * 默认请求头
+ */
+ public static String DEFAULT_ACCESS_HEADER;
+
+ /**
+ * 默认 accessToken
+ */
+ public static String DEFAULT_ACCESS_TOKEN;
+
+ /**
+ * agent 文件名称前缀
+ */
+ public static final String AGENT_FILE_NAME_PREFIX = "machine-monitor-agent";
+
+ /**
+ * 启动脚本资源路径
+ */
+ public static final String START_SCRIPT_PATH = "/templates/script/start-monitor-agent.sh";
+
+ /**
+ * 启动脚本资源内容
+ */
+ public static final String START_SCRIPT_VALUE = ResourceLoader.get(START_SCRIPT_PATH, MonitorConst.class);
+
+ /**
+ * 启动脚本文件名称
+ */
+ public static final String START_SCRIPT_FILE_NAME = "start-machine-monitor-agent.sh";
+
+ @Value("${machine.monitor.latest.version}")
+ private void setLatestVersion(String latestVersion) {
+ MonitorConst.LATEST_VERSION = latestVersion;
+ }
+
+ @Value("${machine.monitor.default.url}")
+ private void setDefaultUrlFormat(String defaultUrlFormat) {
+ MonitorConst.DEFAULT_URL_FORMAT = defaultUrlFormat;
+ }
+
+ @Value("${machine.monitor.default.access.header}")
+ private void setDefaultAccessHeader(String defaultAccessHeader) {
+ MonitorConst.DEFAULT_ACCESS_HEADER = defaultAccessHeader;
+ }
+
+ @Value("${machine.monitor.default.access.token}")
+ private void setDefaultAccessToken(String defaultAccessToken) {
+ MonitorConst.DEFAULT_ACCESS_TOKEN = defaultAccessToken;
+ }
+
+ /**
+ * agent 文件名称
+ *
+ * @return 获取 agent 文件名称
+ */
+ public static String getAgentFileName() {
+ return AGENT_FILE_NAME_PREFIX
+ + "_" + PropertiesConst.MACHINE_MONITOR_LATEST_VERSION
+ + "." + Const.SUFFIX_JAR;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/monitor/MonitorStatus.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/monitor/MonitorStatus.java
new file mode 100644
index 0000000..1d0434a
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/monitor/MonitorStatus.java
@@ -0,0 +1,41 @@
+package cn.orionsec.ops.constant.monitor;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum MonitorStatus {
+
+ /**
+ * 未启动
+ */
+ NOT_START(1),
+
+ /**
+ * 启动中
+ */
+ STARTING(2),
+
+ /**
+ * 运行中
+ */
+ RUNNING(3),
+
+ ;
+
+ private final Integer status;
+
+ public static MonitorStatus of(Integer status) {
+ if (status == null) {
+ return null;
+ }
+ for (MonitorStatus value : values()) {
+ if (value.status.equals(status)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/scheduler/SchedulerTaskMachineStatus.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/scheduler/SchedulerTaskMachineStatus.java
new file mode 100644
index 0000000..f23a48b
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/scheduler/SchedulerTaskMachineStatus.java
@@ -0,0 +1,56 @@
+package cn.orionsec.ops.constant.scheduler;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public enum SchedulerTaskMachineStatus {
+
+ /**
+ * 待调度
+ */
+ WAIT(10),
+
+ /**
+ * 执行中
+ */
+ RUNNABLE(20),
+
+ /**
+ * 成功
+ */
+ SUCCESS(30),
+
+ /**
+ * 失败
+ */
+ FAILURE(40),
+
+ /**
+ * 已跳过
+ */
+ SKIPPED(50),
+
+ /**
+ * 已停止
+ */
+ TERMINATED(60),
+
+ ;
+
+ private final Integer status;
+
+ public static SchedulerTaskMachineStatus of(Integer status) {
+ if (status == null) {
+ return null;
+ }
+ for (SchedulerTaskMachineStatus value : values()) {
+ if (value.status.equals(status)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/scheduler/SchedulerTaskStatus.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/scheduler/SchedulerTaskStatus.java
new file mode 100644
index 0000000..4f60afe
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/scheduler/SchedulerTaskStatus.java
@@ -0,0 +1,51 @@
+package cn.orionsec.ops.constant.scheduler;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public enum SchedulerTaskStatus {
+
+ /**
+ * 待调度
+ */
+ WAIT(10),
+
+ /**
+ * 执行中
+ */
+ RUNNABLE(20),
+
+ /**
+ * 成功
+ */
+ SUCCESS(30),
+
+ /**
+ * 失败
+ */
+ FAILURE(40),
+
+ /**
+ * 已停止
+ */
+ TERMINATED(50),
+
+ ;
+
+ private final Integer status;
+
+ public static SchedulerTaskStatus of(Integer status) {
+ if (status == null) {
+ return null;
+ }
+ for (SchedulerTaskStatus value : values()) {
+ if (value.status.equals(status)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/sftp/SftpNotifyType.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/sftp/SftpNotifyType.java
new file mode 100644
index 0000000..b6cb9e3
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/sftp/SftpNotifyType.java
@@ -0,0 +1,41 @@
+package cn.orionsec.ops.constant.sftp;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum SftpNotifyType {
+
+ /**
+ * 添加任务
+ */
+ ADD(10),
+
+ /**
+ * 进度以及速率
+ */
+ PROGRESS(20),
+
+ /**
+ * 修改状态
+ */
+ CHANGE_STATUS(30),
+
+ ;
+
+ private final Integer type;
+
+ public static SftpNotifyType of(Integer type) {
+ if (type == null) {
+ return null;
+ }
+ for (SftpNotifyType value : values()) {
+ if (value.type.equals(type)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/sftp/SftpPackageType.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/sftp/SftpPackageType.java
new file mode 100644
index 0000000..e741c43
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/sftp/SftpPackageType.java
@@ -0,0 +1,41 @@
+package cn.orionsec.ops.constant.sftp;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum SftpPackageType {
+
+ /**
+ * 上传文件
+ */
+ UPLOAD(1),
+
+ /**
+ * 下载文件
+ */
+ DOWNLOAD(2),
+
+ /**
+ * 全部
+ */
+ ALL(3),
+
+ ;
+
+ private final Integer type;
+
+ public static SftpPackageType of(Integer type) {
+ if (type == null) {
+ return null;
+ }
+ for (SftpPackageType value : values()) {
+ if (value.type.equals(type)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/sftp/SftpTransferStatus.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/sftp/SftpTransferStatus.java
new file mode 100644
index 0000000..9ce9cc0
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/sftp/SftpTransferStatus.java
@@ -0,0 +1,56 @@
+package cn.orionsec.ops.constant.sftp;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum SftpTransferStatus {
+
+ /**
+ * 10 等待中
+ */
+ WAIT(10),
+
+ /**
+ * 20 进行中
+ */
+ RUNNABLE(20),
+
+ /**
+ * 30 已暂停
+ */
+ PAUSE(30),
+
+ /**
+ * 40 已完成
+ */
+ FINISH(40),
+
+ /**
+ * 50 已取消
+ */
+ CANCEL(50),
+
+ /**
+ * 60 传输异常
+ */
+ ERROR(60),
+
+ ;
+
+ private final Integer status;
+
+ public static SftpTransferStatus of(Integer status) {
+ if (status == null) {
+ return null;
+ }
+ for (SftpTransferStatus value : values()) {
+ if (value.status.equals(status)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/sftp/SftpTransferType.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/sftp/SftpTransferType.java
new file mode 100644
index 0000000..c8c4852
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/sftp/SftpTransferType.java
@@ -0,0 +1,48 @@
+package cn.orionsec.ops.constant.sftp;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum SftpTransferType {
+
+ /**
+ * 10 上传
+ */
+ UPLOAD(10, "上传"),
+
+ /**
+ * 20 下载
+ */
+ DOWNLOAD(20, "下载"),
+
+ /**
+ * 30 传输
+ */
+ TRANSFER(30, "传输"),
+
+ /**
+ * 40 打包
+ */
+ PACKAGE(40, "打包"),
+
+ ;
+
+ private final Integer type;
+
+ private final String label;
+
+ public static SftpTransferType of(Integer type) {
+ if (type == null) {
+ return null;
+ }
+ for (SftpTransferType value : values()) {
+ if (value.type.equals(type)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/system/SystemCleanType.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/system/SystemCleanType.java
new file mode 100644
index 0000000..d655b9e
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/system/SystemCleanType.java
@@ -0,0 +1,58 @@
+package cn.orionsec.ops.constant.system;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+@AllArgsConstructor
+@Getter
+public enum SystemCleanType {
+
+ /**
+ * 临时文件
+ */
+ TEMP_FILE(10, "临时文件"),
+
+ /**
+ * 日志文件
+ */
+ LOG_FILE(20, "日志文件"),
+
+ /**
+ * 交换文件
+ */
+ SWAP_FILE(30, "交换文件"),
+
+ /**
+ * 历史产物文件
+ */
+ DIST_FILE(40, "旧版本构建产物"),
+
+ /**
+ * 版本仓库文件
+ */
+ REPO_FILE(50, "旧版本应用仓库"),
+
+ /**
+ * 录屏文件
+ */
+ SCREEN_FILE(60, "录屏文件"),
+
+ ;
+
+ private final Integer type;
+
+ private final String label;
+
+ public static SystemCleanType of(Integer type) {
+ if (type == null) {
+ return null;
+ }
+ return Arrays.stream(values())
+ .filter(a -> a.type.equals(type))
+ .findFirst()
+ .orElse(null);
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/system/SystemConfigKey.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/system/SystemConfigKey.java
new file mode 100644
index 0000000..66aa097
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/system/SystemConfigKey.java
@@ -0,0 +1,256 @@
+package cn.orionsec.ops.constant.system;
+
+import cn.orionsec.kit.lang.exception.argument.InvalidArgumentException;
+import cn.orionsec.kit.lang.function.Conversion;
+import cn.orionsec.kit.lang.utils.Exceptions;
+import cn.orionsec.kit.lang.utils.Strings;
+import cn.orionsec.kit.lang.utils.Valid;
+import cn.orionsec.ops.constant.MessageConst;
+import cn.orionsec.ops.constant.common.EnableType;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+@AllArgsConstructor
+@Getter
+public enum SystemConfigKey {
+
+ /**
+ * 文件清理阈值 (天)
+ */
+ FILE_CLEAN_THRESHOLD(10, SystemEnvAttr.FILE_CLEAN_THRESHOLD) {
+ @Override
+ protected boolean valid(String s) {
+ return Strings.isInteger(s) && Integer.parseInt(s) >= 0 && Integer.parseInt(s) <= 1000;
+ }
+
+ @Override
+ protected String validTips() {
+ return FILE_CLEAN_THRESHOLD_TIPS;
+ }
+ },
+
+ /**
+ * 是否启用自动清理
+ */
+ ENABLE_AUTO_CLEAN_FILE(20, SystemEnvAttr.ENABLE_AUTO_CLEAN_FILE) {
+ @Override
+ protected String conversionValue(String s) {
+ return ENABLED_TYPE.apply(s);
+ }
+ },
+
+ /**
+ * 是否允许多端登录
+ */
+ ALLOW_MULTIPLE_LOGIN(30, SystemEnvAttr.ALLOW_MULTIPLE_LOGIN) {
+ @Override
+ protected String conversionValue(String s) {
+ return ENABLED_TYPE.apply(s);
+ }
+ },
+
+ /**
+ * 是否启用登录失败锁定
+ */
+ LOGIN_FAILURE_LOCK(40, SystemEnvAttr.LOGIN_FAILURE_LOCK) {
+ @Override
+ protected String conversionValue(String s) {
+ return ENABLED_TYPE.apply(s);
+ }
+ },
+
+ /**
+ * 是否启用登录IP绑定
+ */
+ LOGIN_IP_BIND(50, SystemEnvAttr.LOGIN_IP_BIND) {
+ @Override
+ protected String conversionValue(String s) {
+ return ENABLED_TYPE.apply(s);
+ }
+ },
+
+ /**
+ * 是否启用凭证自动续签
+ */
+ LOGIN_TOKEN_AUTO_RENEW(60, SystemEnvAttr.LOGIN_TOKEN_AUTO_RENEW) {
+ @Override
+ protected String conversionValue(String s) {
+ return ENABLED_TYPE.apply(s);
+ }
+ },
+
+ /**
+ * 登录凭证有效期 (时)
+ */
+ LOGIN_TOKEN_EXPIRE(70, SystemEnvAttr.LOGIN_TOKEN_EXPIRE) {
+ @Override
+ protected boolean valid(String s) {
+ return Strings.isInteger(s) && Integer.parseInt(s) > 0 && Integer.parseInt(s) <= 720;
+ }
+
+ @Override
+ protected String validTips() {
+ return LOGIN_TOKEN_EXPIRE_TIPS;
+ }
+ },
+
+ /**
+ * 登录失败锁定阈值 (次)
+ */
+ LOGIN_FAILURE_LOCK_THRESHOLD(80, SystemEnvAttr.LOGIN_FAILURE_LOCK_THRESHOLD) {
+ @Override
+ protected boolean valid(String s) {
+ return Strings.isInteger(s) && Integer.parseInt(s) > 0 && Integer.parseInt(s) <= 100;
+ }
+
+ @Override
+ protected String validTips() {
+ return LOGIN_FAILURE_LOCK_THRESHOLD_TIPS;
+ }
+ },
+
+ /**
+ * 登录自动续签阈值 (时)
+ */
+ LOGIN_TOKEN_AUTO_RENEW_THRESHOLD(90, SystemEnvAttr.LOGIN_TOKEN_AUTO_RENEW_THRESHOLD) {
+ @Override
+ protected boolean valid(String s) {
+ return Strings.isInteger(s) && Integer.parseInt(s) > 0 && Integer.parseInt(s) <= 720;
+ }
+
+ @Override
+ protected String validTips() {
+ return LOGIN_TOKEN_AUTO_RENEW_THRESHOLD_TIPS;
+ }
+ },
+
+ /**
+ * 自动恢复启用的调度任务
+ */
+ RESUME_ENABLE_SCHEDULER_TASK(100, SystemEnvAttr.RESUME_ENABLE_SCHEDULER_TASK) {
+ @Override
+ protected String conversionValue(String s) {
+ return ENABLED_TYPE.apply(s);
+ }
+ },
+
+ /**
+ * SFTP 上传文件最大阈值 (MB)
+ */
+ SFTP_UPLOAD_THRESHOLD(110, SystemEnvAttr.SFTP_UPLOAD_THRESHOLD) {
+ @Override
+ protected boolean valid(String s) {
+ return Strings.isInteger(s) && Integer.parseInt(s) >= 10 && Integer.parseInt(s) <= 2048;
+ }
+
+ @Override
+ protected String validTips() {
+ return SFTP_UPLOAD_THRESHOLD_TIPS;
+ }
+ },
+
+ /**
+ * 统计缓存有效时间 (分)
+ */
+ STATISTICS_CACHE_EXPIRE(120, SystemEnvAttr.STATISTICS_CACHE_EXPIRE) {
+ @Override
+ protected boolean valid(String s) {
+ return Strings.isInteger(s) && Integer.parseInt(s) > 0 && Integer.parseInt(s) <= 10080;
+ }
+
+ @Override
+ protected String validTips() {
+ return STATISTICS_CACHE_EXPIRE_TIPS;
+ }
+ },
+
+ /**
+ * 终端后台主动推送心跳
+ */
+ TERMINAL_ACTIVE_PUSH_HEARTBEAT(130, SystemEnvAttr.TERMINAL_ACTIVE_PUSH_HEARTBEAT) {
+ @Override
+ protected String conversionValue(String s) {
+ return ENABLED_TYPE.apply(s);
+ }
+ },
+
+ ;
+
+ private static final String FILE_CLEAN_THRESHOLD_TIPS = "文件清理阈值需要在 10 ~ 2048 之间";
+
+ private static final String LOGIN_TOKEN_EXPIRE_TIPS = "登录凭证有效期需要在 1 ~ 720 之间";
+
+ private static final String LOGIN_FAILURE_LOCK_THRESHOLD_TIPS = "登录失败锁定阈值需要在 1 ~ 100 之间";
+
+ private static final String LOGIN_TOKEN_AUTO_RENEW_THRESHOLD_TIPS = "登录自动续签阈值需要在 1 ~ 720 之间";
+
+ private static final String SFTP_UPLOAD_THRESHOLD_TIPS = "上传文件阈值需要在 10 ~ 2048 之间";
+
+ private static final String STATISTICS_CACHE_EXPIRE_TIPS = "统计缓存有效时间需要在 1 ~ 10080 之间";
+
+ private static final Conversion ENABLED_TYPE = s -> EnableType.of(Boolean.valueOf(s)).getLabel();
+
+ private final Integer type;
+
+ private final SystemEnvAttr env;
+
+ /**
+ * 验证
+ *
+ * @param s s
+ * @return value
+ */
+ protected boolean valid(String s) {
+ return true;
+ }
+
+ /**
+ * 验证失败提示
+ *
+ * @return 验证失败提示
+ */
+ protected String validTips() {
+ return MessageConst.INVALID_CONFIG;
+ }
+
+ /**
+ * 转化值
+ *
+ * @param s s
+ * @return value
+ */
+ protected String conversionValue(String s) {
+ return s;
+ }
+
+ /**
+ * 获取值
+ *
+ * @return value
+ */
+ public String getValue(String s) {
+ // 验证
+ try {
+ Valid.isTrue(this.valid(s), this.validTips());
+ } catch (InvalidArgumentException e) {
+ throw e;
+ } catch (Exception e) {
+ throw Exceptions.argument(this.validTips());
+ }
+ // 转化
+ return this.conversionValue(s);
+ }
+
+ public static SystemConfigKey of(Integer type) {
+ if (type == null) {
+ return null;
+ }
+ return Arrays.stream(values())
+ .filter(a -> a.type.equals(type))
+ .findFirst()
+ .orElse(null);
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/system/SystemEnvAttr.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/system/SystemEnvAttr.java
new file mode 100644
index 0000000..bc96ddf
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/system/SystemEnvAttr.java
@@ -0,0 +1,197 @@
+package cn.orionsec.ops.constant.system;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Getter
+public enum SystemEnvAttr {
+
+ /**
+ * 密钥存放目录
+ */
+ KEY_PATH("密钥存放目录", false),
+
+ /**
+ * 图片存放目录
+ */
+ PIC_PATH("图片存放目录", false),
+
+ /**
+ * 交换分区目录
+ */
+ SWAP_PATH("交换分区目录", false),
+
+ /**
+ * 录屏存放目录
+ */
+ SCREEN_PATH("录屏存放目录", false),
+
+ /**
+ * 日志存放目录
+ */
+ LOG_PATH("日志存放目录", false),
+
+ /**
+ * 临时文件目录
+ */
+ TEMP_PATH("临时文件目录", false),
+
+ /**
+ * 应用版本仓库目录
+ */
+ REPO_PATH("应用版本仓库目录", false),
+
+ /**
+ * 构建产物目录
+ */
+ DIST_PATH("构建产物目录", false),
+
+ /**
+ * 机器监控插件绝对路径
+ */
+ MACHINE_MONITOR_AGENT_PATH("机器监控插件绝对路径", false),
+
+ /**
+ * 日志文件上传目录
+ */
+ TAIL_FILE_UPLOAD_PATH("日志文件上传目录", false),
+
+ /**
+ * 日志文件追踪模式 tracker或tail 默认tracker
+ */
+ TAIL_MODE("日志文件追踪模式 (tracker/tail)", false),
+
+ /**
+ * 文件追踪器等待时间 (ms)
+ */
+ TRACKER_DELAY_TIME("文件追踪器等待时间 (ms)", false),
+
+ /**
+ * ip 白名单
+ */
+ WHITE_IP_LIST("ip 白名单", true),
+
+ /**
+ * ip 黑名单
+ */
+ BLACK_IP_LIST("ip 黑名单", true),
+
+ /**
+ * 是否启用 IP 过滤
+ */
+ ENABLE_IP_FILTER("是否启用IP过滤", true),
+
+ /**
+ * 是否启用 IP 白名单
+ */
+ ENABLE_WHITE_IP_LIST("是否启用IP白名单", true),
+
+ /**
+ * 文件清理阈值 (天)
+ */
+ FILE_CLEAN_THRESHOLD("文件清理阈值 (天)", true),
+
+ /**
+ * 是否启用自动清理
+ */
+ ENABLE_AUTO_CLEAN_FILE("是否启用自动清理", true),
+
+ /**
+ * 是否允许多端登录
+ */
+ ALLOW_MULTIPLE_LOGIN("允许多端登录", true),
+
+ /**
+ * 是否启用登录失败锁定
+ */
+ LOGIN_FAILURE_LOCK("是否启用登录失败锁定", true),
+
+ /**
+ * 是否启用登录IP绑定
+ */
+ LOGIN_IP_BIND("是否启用登录IP绑定", true),
+
+ /**
+ * 是否启用凭证自动续签
+ */
+ LOGIN_TOKEN_AUTO_RENEW("是否启用凭证自动续签", true),
+
+ /**
+ * 登录凭证有效期 (时)
+ */
+ LOGIN_TOKEN_EXPIRE("登录凭证有效期 (时)", true),
+
+ /**
+ * 登录失败锁定阈值 (次)
+ */
+ LOGIN_FAILURE_LOCK_THRESHOLD("登录失败锁定阈值", true),
+
+ /**
+ * 登录自动续签阈值 (时)
+ */
+ LOGIN_TOKEN_AUTO_RENEW_THRESHOLD("登录自动续签阈值 (时)", true),
+
+ /**
+ * 自动恢复启用的调度任务
+ */
+ RESUME_ENABLE_SCHEDULER_TASK("自动恢复启用的调度任务", true),
+
+ /**
+ * 终端后台主动推送心跳
+ */
+ TERMINAL_ACTIVE_PUSH_HEARTBEAT("终端后台主动推送心跳", true),
+
+ /**
+ * SFTP 上传文件最大阈值 (MB)
+ */
+ SFTP_UPLOAD_THRESHOLD("sftp 上传文件最大阈值 (MB)", true),
+
+ /**
+ * 统计缓存有效时间 (分)
+ */
+ STATISTICS_CACHE_EXPIRE("统计缓存有效时间 (分)", true),
+
+ ;
+
+ /**
+ * key
+ */
+ private final String key;
+
+ /**
+ * 描述
+ */
+ private final String description;
+
+ private final boolean systemEnv;
+
+ @Setter
+ private String value;
+
+ SystemEnvAttr(String description, boolean systemEnv) {
+ this.description = description;
+ this.systemEnv = systemEnv;
+ this.key = this.name().toLowerCase();
+ }
+
+ public static List getKeys() {
+ return Arrays.stream(values())
+ .map(SystemEnvAttr::getKey)
+ .collect(Collectors.toList());
+ }
+
+ public static SystemEnvAttr of(String key) {
+ if (key == null) {
+ return null;
+ }
+ return Arrays.stream(values())
+ .filter(a -> a.key.equals(key))
+ .findFirst()
+ .orElse(null);
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/system/ThreadPoolMetricsType.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/system/ThreadPoolMetricsType.java
new file mode 100644
index 0000000..72cf07c
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/system/ThreadPoolMetricsType.java
@@ -0,0 +1,89 @@
+package cn.orionsec.ops.constant.system;
+
+import cn.orionsec.ops.constant.SchedulerPools;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.concurrent.ThreadPoolExecutor;
+
+@AllArgsConstructor
+@Getter
+public enum ThreadPoolMetricsType {
+
+ /**
+ * terminal
+ */
+ TERMINAL(10, SchedulerPools.TERMINAL_SCHEDULER),
+
+ /**
+ * terminal watcher
+ */
+ TERMINAL_WATCHER(15, SchedulerPools.TERMINAL_WATCHER_SCHEDULER),
+
+ /**
+ * 命令执行
+ */
+ EXEC(20, SchedulerPools.EXEC_SCHEDULER),
+
+ /**
+ * tail
+ */
+ TAIL(30, SchedulerPools.TAIL_SCHEDULER),
+
+ /**
+ * sftp 传输进度
+ */
+ SFTP_TRANSFER_RATE(40, SchedulerPools.SFTP_TRANSFER_RATE_SCHEDULER),
+
+ /**
+ * sftp 上传
+ */
+ SFTP_UPLOAD(50, SchedulerPools.SFTP_UPLOAD_SCHEDULER),
+
+ /**
+ * sftp 下载
+ */
+ SFTP_DOWNLOAD(60, SchedulerPools.SFTP_DOWNLOAD_SCHEDULER),
+
+ /**
+ * sftp 打包
+ */
+ SFTP_PACKAGE(70, SchedulerPools.SFTP_PACKAGE_SCHEDULER),
+
+ /**
+ * 应用构建
+ */
+ APP_BUILD(80, SchedulerPools.APP_BUILD_SCHEDULER),
+
+ /**
+ * 应用发布 主线程
+ */
+ RELEASE_MAIN(90, SchedulerPools.RELEASE_MAIN_SCHEDULER),
+
+ /**
+ * 应用发布 机器操作
+ */
+ RELEASE_MACHINE(100, SchedulerPools.RELEASE_MACHINE_SCHEDULER),
+
+ /**
+ * 调度任务 主线程
+ */
+ SCHEDULER_TASK_MAIN(110, SchedulerPools.SCHEDULER_TASK_MAIN_SCHEDULER),
+
+ /**
+ * 调度任务 机器操作
+ */
+ SCHEDULER_TASK_MACHINE(120, SchedulerPools.SCHEDULER_TASK_MACHINE_SCHEDULER),
+
+ /**
+ * 应用流水线
+ */
+ PIPELINE(130, SchedulerPools.PIPELINE_SCHEDULER),
+
+ ;
+
+ private final Integer type;
+
+ private final ThreadPoolExecutor executor;
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/tail/FileTailMode.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/tail/FileTailMode.java
new file mode 100644
index 0000000..1515776
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/tail/FileTailMode.java
@@ -0,0 +1,59 @@
+package cn.orionsec.ops.constant.tail;
+
+import cn.orionsec.kit.lang.utils.Strings;
+import cn.orionsec.ops.constant.system.SystemEnvAttr;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public enum FileTailMode {
+
+ /**
+ * 仅宿主机
+ *
+ * @see cn.orionsec.ops.tail.Tracker
+ * @see cn.orionsec.ops.handler.tail.impl.TrackerTailFileHandler
+ */
+ TRACKER("tracker"),
+
+ /**
+ * tail 命令
+ *
+ * 宿主机 远程机器
+ *
+ * @see cn.orionsec.ops.handler.tail.impl.ExecTailFileHandler
+ */
+ TAIL("tail"),
+
+ ;
+
+ private final String mode;
+
+ public static FileTailMode of(String mode) {
+ return of(mode, false);
+ }
+
+ public static FileTailMode of(String mode, boolean hostMachine) {
+ if (Strings.isBlank(mode)) {
+ return hostMachine ? TRACKER : TAIL;
+ }
+ for (FileTailMode value : values()) {
+ if (value.mode.equals(mode)) {
+ return value;
+ }
+ }
+ return hostMachine ? TRACKER : TAIL;
+ }
+
+ /**
+ * 获取宿主机 tailMode
+ *
+ * @return tailMode
+ */
+ public static String getHostTailMode() {
+ String mode = SystemEnvAttr.TAIL_MODE.getValue();
+ return of(mode, true).getMode();
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/tail/FileTailType.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/tail/FileTailType.java
new file mode 100644
index 0000000..8a1a0b8
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/tail/FileTailType.java
@@ -0,0 +1,72 @@
+package cn.orionsec.ops.constant.tail;
+
+import cn.orionsec.ops.constant.system.SystemEnvAttr;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public enum FileTailType {
+
+ /**
+ * 命令执行日志
+ *
+ * @see SystemEnvAttr#LOG_PATH
+ */
+ EXEC_LOG(10, true),
+
+ /**
+ * tail 列表
+ */
+ TAIL_LIST(20, false),
+
+ /**
+ * 应用构建日志
+ *
+ * @see SystemEnvAttr#LOG_PATH
+ */
+ APP_BUILD_LOG(30, true),
+
+ /**
+ * 应用发布日志
+ *
+ * @see SystemEnvAttr#LOG_PATH
+ */
+ APP_RELEASE_LOG(40, true),
+
+ /**
+ * 调度任务机器日志
+ *
+ * @see SystemEnvAttr#LOG_PATH
+ */
+ SCHEDULER_TASK_MACHINE_LOG(50, true),
+
+ /**
+ * 应用操作日志
+ *
+ * @see SystemEnvAttr#LOG_PATH
+ */
+ APP_ACTION_LOG(60, true),
+
+ ;
+
+ private final Integer type;
+
+ /**
+ * 是否为本地文件
+ */
+ private final boolean isLocal;
+
+ public static FileTailType of(Integer type) {
+ if (type == null) {
+ return null;
+ }
+ for (FileTailType value : values()) {
+ if (value.type.equals(type)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/terminal/TerminalClientOperate.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/terminal/TerminalClientOperate.java
new file mode 100644
index 0000000..ad0d47b
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/terminal/TerminalClientOperate.java
@@ -0,0 +1,65 @@
+package cn.orionsec.ops.constant.terminal;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public enum TerminalClientOperate {
+
+ /**
+ * 键入
+ */
+ KEY("0", true),
+
+ /**
+ * 连接
+ */
+ CONNECT("1", true),
+
+ /**
+ * ping
+ */
+ PING("2", false),
+
+ /**
+ * pong
+ */
+ PONG("3", false),
+
+ /**
+ * 更改大小
+ */
+ RESIZE("4", true),
+
+ /**
+ * 键入命令
+ */
+ COMMAND("5", true),
+
+ /**
+ * ctrl + l
+ */
+ CLEAR("6", false),
+
+ ;
+
+ /**
+ * 前缀长度
+ */
+ public static final int PREFIX_SIZE = 1;
+
+ private final String operate;
+
+ private final boolean hasBody;
+
+ public static TerminalClientOperate of(String operate) {
+ for (TerminalClientOperate value : values()) {
+ if (value.operate.equals(operate)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/terminal/TerminalConst.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/terminal/TerminalConst.java
new file mode 100644
index 0000000..c2440ef
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/terminal/TerminalConst.java
@@ -0,0 +1,40 @@
+package cn.orionsec.ops.constant.terminal;
+
+import cn.orionsec.ops.constant.Const;
+
+public class TerminalConst {
+
+ private TerminalConst() {
+ }
+
+ /**
+ * 判断终端心跳断开的阀值
+ */
+ public static final int TERMINAL_CONNECT_DOWN = Const.MS_S_60 + Const.MS_S_15;
+
+ /**
+ * terminal symbol
+ */
+ public static final String TERMINAL = "terminal";
+
+ /**
+ * 默认背景色
+ */
+ public static final String BACKGROUND_COLOR = "#212529";
+
+ /**
+ * 默认字体颜色
+ */
+ public static final String FONT_COLOR = "#FFFFFF";
+
+ /**
+ * 默认字体大小
+ */
+ public static final int FONT_SIZE = 14;
+
+ /**
+ * 默认字体名称
+ */
+ public static final String FONT_FAMILY = "courier-new, courier, monospace";
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/user/RoleType.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/user/RoleType.java
new file mode 100644
index 0000000..af6ab82
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/user/RoleType.java
@@ -0,0 +1,56 @@
+package cn.orionsec.ops.constant.user;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public enum RoleType {
+
+ /**
+ * 管理员
+ */
+ ADMINISTRATOR(10, "/menu/menu-admin.json"),
+
+ /**
+ * 开发
+ */
+ DEVELOPER(20, "/menu/menu-dev.json"),
+
+ /**
+ * 运维
+ */
+ OPERATION(30, "/menu/menu-opt.json"),
+
+ ;
+
+ private final Integer type;
+
+ private final String menuPath;
+
+ public static RoleType of(Integer type) {
+ if (type == null) {
+ return null;
+ }
+ for (RoleType value : values()) {
+ if (value.type.equals(type)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * 是否为 管理员
+ *
+ * @return true 管理员
+ */
+ public static boolean isAdministrator(Integer type) {
+ RoleType role = of(type);
+ if (role == null) {
+ return false;
+ }
+ return ADMINISTRATOR.equals(role);
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/webhook/WebhookType.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/webhook/WebhookType.java
new file mode 100644
index 0000000..c018c67
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/webhook/WebhookType.java
@@ -0,0 +1,45 @@
+package cn.orionsec.ops.constant.webhook;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum WebhookType {
+
+ /**
+ * 钉钉机器人
+ */
+ DING_ROBOT(10, "钉钉机器人"),
+
+ ;
+
+ private final Integer type;
+
+ private final String label;
+
+ public static WebhookType of(Integer type) {
+ if (type == null) {
+ return null;
+ }
+ for (WebhookType value : values()) {
+ if (value.type.equals(type)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+ public static WebhookType of(String label) {
+ if (label == null) {
+ return null;
+ }
+ for (WebhookType value : values()) {
+ if (value.label.equals(label)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/ws/WsCloseCode.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/ws/WsCloseCode.java
new file mode 100644
index 0000000..f499e51
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/ws/WsCloseCode.java
@@ -0,0 +1,130 @@
+package cn.orionsec.ops.constant.ws;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public enum WsCloseCode {
+
+ /**
+ * 未查询到token
+ */
+ INCORRECT_TOKEN(4100, WsCloseReason.CLOSED_CONNECTION),
+
+ /**
+ * 伪造token
+ */
+ FORGE_TOKEN(4120, WsCloseReason.CLOSED_CONNECTION),
+
+ /**
+ * token已被绑定
+ */
+ TOKEN_BIND(4125, WsCloseReason.CLOSED_CONNECTION),
+
+ /**
+ * 未知的连接
+ */
+ UNKNOWN_CONNECT(4130, WsCloseReason.CLOSED_CONNECTION),
+
+ /**
+ * 认证失败 id不匹配
+ */
+ IDENTITY_MISMATCH(4140, WsCloseReason.IDENTITY_MISMATCH),
+
+ /**
+ * 认证信息不匹配
+ */
+ VALID(4150, WsCloseReason.AUTHENTICATION_FAILURE),
+
+ /**
+ * 机器不合法
+ */
+ INVALID_MACHINE(4200, WsCloseReason.CLOSED_CONNECTION),
+
+ /**
+ * 连接远程服务器连接超时
+ */
+ CONNECTION_TIMEOUT(4201, WsCloseReason.CONNECTION_TIMEOUT),
+
+ /**
+ * 连接远程服务器失败
+ */
+ CONNECTION_FAILURE(4202, WsCloseReason.REMOTE_SERVER_UNREACHABLE),
+
+ /**
+ * 远程服务器认证失败
+ */
+ CONNECTION_AUTH_FAILURE(4205, WsCloseReason.REMOTE_SERVER_AUTHENTICATION_FAILURE),
+
+ /**
+ * 远程服务器认证出现异常
+ */
+ CONNECTION_EXCEPTION(4210, WsCloseReason.UNABLE_TO_CONNECT_REMOTE_SERVER),
+
+ /**
+ * 机器未启用
+ */
+ MACHINE_DISABLED(4215, WsCloseReason.MACHINE_DISABLED),
+
+ /**
+ * 打开shell出现异常
+ */
+ OPEN_SHELL_EXCEPTION(4220, WsCloseReason.UNABLE_TO_CONNECT_REMOTE_SERVER),
+
+ /**
+ * 打开command出现异常
+ */
+ OPEN_COMMAND_EXCEPTION(4225, WsCloseReason.UNABLE_TO_CONNECT_REMOTE_SERVER),
+
+ /**
+ * 打开sftp出现异常
+ */
+ OPEN_SFTP_EXCEPTION(4230, WsCloseReason.UNABLE_TO_CONNECT_REMOTE_SERVER),
+
+ /**
+ * 服务出现异常
+ */
+ RUNTIME_EXCEPTION(4300, WsCloseReason.CLOSED_CONNECTION),
+
+ /**
+ * 心跳结束
+ */
+ HEART_DOWN(4310, WsCloseReason.CLOSED_CONNECTION),
+
+ /**
+ * 用户关闭
+ */
+ DISCONNECT(4320, WsCloseReason.CLOSED_CONNECTION),
+
+ /**
+ * 结束
+ */
+ EOF(4330, WsCloseReason.CLOSED_CONNECTION),
+
+ /**
+ * 读取失败
+ */
+ READ_EXCEPTION(4335, WsCloseReason.CLOSED_CONNECTION),
+
+ /**
+ * 强制下线
+ */
+ FORCED_OFFLINE(4500, WsCloseReason.FORCED_OFFLINE),
+
+ ;
+
+ private final int code;
+
+ private final String reason;
+
+ public static WsCloseCode of(int code) {
+ for (WsCloseCode value : values()) {
+ if (value.code == code) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/ws/WsCloseReason.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/ws/WsCloseReason.java
new file mode 100644
index 0000000..716bb67
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/ws/WsCloseReason.java
@@ -0,0 +1,27 @@
+package cn.orionsec.ops.constant.ws;
+
+
+public class WsCloseReason {
+
+ private WsCloseReason() {
+ }
+
+ public static final String CLOSED_CONNECTION = "closed connection...";
+
+ public static final String IDENTITY_MISMATCH = "identity mismatch...";
+
+ public static final String AUTHENTICATION_FAILURE = "authentication failure...";
+
+ public static final String REMOTE_SERVER_UNREACHABLE = "remote server unreachable...";
+
+ public static final String CONNECTION_TIMEOUT = "connection timeout...";
+
+ public static final String REMOTE_SERVER_AUTHENTICATION_FAILURE = "remote server authentication failure...";
+
+ public static final String MACHINE_DISABLED = "machine disabled...";
+
+ public static final String UNABLE_TO_CONNECT_REMOTE_SERVER = "unable to connect remote server...";
+
+ public static final String FORCED_OFFLINE = "forced offline...";
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/ws/WsProtocol.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/ws/WsProtocol.java
new file mode 100644
index 0000000..d419104
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/constant/ws/WsProtocol.java
@@ -0,0 +1,73 @@
+package cn.orionsec.ops.constant.ws;
+
+import cn.orionsec.kit.lang.utils.Exceptions;
+import cn.orionsec.kit.lang.utils.Strings;
+import cn.orionsec.kit.lang.utils.Valid;
+import lombok.AllArgsConstructor;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+
+@AllArgsConstructor
+public enum WsProtocol {
+
+ /**
+ * 正常返回
+ */
+ OK("0"),
+
+ /**
+ * 连接成功
+ */
+ CONNECTED("1"),
+
+ /**
+ * ping
+ */
+ PING("2"),
+
+ /**
+ * pong
+ */
+ PONG("3"),
+
+ /**
+ * 未知操作
+ */
+ ERROR("4"),
+
+ ;
+
+ private final String code;
+
+ /**
+ * 分隔符
+ */
+ public static final String SYMBOL = "|";
+
+ public byte[] get() {
+ return Strings.bytes(code);
+ }
+
+ public byte[] msg(String body) {
+ Valid.notNull(body);
+ return this.msg(Strings.bytes(body));
+ }
+
+ public byte[] msg(byte[] body) {
+ return this.msg(body, 0, body.length);
+ }
+
+ public byte[] msg(byte[] body, int offset, int len) {
+ Valid.notNull(body);
+ try (ByteArrayOutputStream o = new ByteArrayOutputStream()) {
+ o.write(Strings.bytes(code + SYMBOL));
+ o.write(body, offset, len);
+ return o.toByteArray();
+ } catch (IOException e) {
+ throw Exceptions.ioRuntime(e);
+ }
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/utils/AttrConverts.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/utils/AttrConverts.java
new file mode 100644
index 0000000..6871c86
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/utils/AttrConverts.java
@@ -0,0 +1,165 @@
+package cn.orionsec.ops.utils;
+
+import cn.orionsec.kit.lang.define.collect.MutableArrayList;
+import cn.orionsec.kit.lang.define.collect.MutableLinkedHashMap;
+import cn.orionsec.kit.lang.utils.Strings;
+import cn.orionsec.kit.lang.utils.collect.Lists;
+import cn.orionsec.kit.lang.utils.collect.Maps;
+import cn.orionsec.kit.lang.utils.ext.dom.*;
+import cn.orionsec.ops.constant.Const;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.parser.Feature;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import org.dom4j.io.OutputFormat;
+import org.yaml.snakeyaml.Yaml;
+
+import java.util.Map;
+
+public class AttrConverts {
+
+ private static final String XML_ROOT_TAG = "root";
+
+ private static final String XML_NODE_TAG = "env";
+
+ private static final String XML_NODE_KEY_ATTR = "key";
+
+ private AttrConverts() {
+ }
+
+ /**
+ * env -> json
+ *
+ * @param attrs env
+ * @return json
+ */
+ public static String toJson(Map attrs) {
+ return JSON.toJSONString(attrs, SerializerFeature.PrettyFormat);
+ }
+
+ /**
+ * env -> xml
+ *
+ * @param attrs env
+ * @return xml
+ */
+ public static String toXml(Map attrs) {
+ DomBuilder builder = DomBuilder.create();
+ DomElement root = builder.createRootElement(XML_ROOT_TAG);
+ attrs.forEach((k, v) -> {
+ DomElement child = new DomElement(XML_NODE_TAG, v);
+ child.addAttributes(XML_NODE_KEY_ATTR, k);
+ if (DomSupport.isEscape(v)) {
+ child.cdata();
+ }
+ root.addChildNode(child);
+ });
+ builder.build();
+ OutputFormat format = new OutputFormat(Const.SPACE_4, true);
+ format.setExpandEmptyElements(true);
+ // 隐藏头
+ format.setSuppressDeclaration(true);
+ return DomSupport.format(builder.getDocument(), format).substring(1);
+ }
+
+ /**
+ * env -> yml
+ *
+ * @param attrs env
+ * @return yml
+ */
+ public static String toYml(Map attrs) {
+ return new Yaml().dumpAsMap(attrs);
+ }
+
+ /**
+ * env -> properties
+ *
+ * @param attrs env
+ * @return properties
+ */
+ public static String toProperties(Map attrs) {
+ StringBuilder sb = new StringBuilder();
+ attrs.forEach((k, v) -> {
+ sb.append(k).append("=").append(v).append(Const.LF);
+ });
+ return sb.toString();
+ }
+
+ /**
+ * json -> env
+ *
+ * @param json xml
+ * @return json
+ */
+ public static MutableLinkedHashMap fromJson(String json) {
+ MutableLinkedHashMap map = Maps.newMutableLinkedMap();
+ JSONObject res = JSON.parseObject(json, Feature.OrderedField);
+ res.forEach((k, v) -> map.put(k, v + Strings.EMPTY));
+ return map;
+ }
+
+ /**
+ * xml -> env
+ *
+ * @param xml xml
+ * @return env
+ */
+ public static MutableLinkedHashMap fromXml(String xml) {
+ MutableLinkedHashMap map = Maps.newMutableLinkedMap();
+ DomNode domNode = DomExt.of(xml).toDomNode().get(XML_NODE_TAG);
+ MutableArrayList list;
+ if (domNode.getValueClass() == String.class) {
+ list = Lists.newMutableList();
+ list.add(domNode);
+ } else {
+ list = domNode.getListValue();
+ }
+ list.forEach(e -> {
+ Map attr = e.getAttr();
+ if (Maps.isEmpty(attr)) {
+ return;
+ }
+ String key = attr.get(XML_NODE_KEY_ATTR);
+ if (Strings.isBlank(key)) {
+ return;
+ }
+ map.put(key, e.getStringValue());
+ });
+ return map;
+ }
+
+ /**
+ * yml -> env
+ *
+ * @param yml yml
+ * @return env
+ */
+ @SuppressWarnings("unchecked")
+ public static MutableLinkedHashMap fromYml(String yml) {
+ return new Yaml().loadAs(yml, MutableLinkedHashMap.class);
+ }
+
+ /**
+ * properties -> env
+ *
+ * @param properties properties
+ * @return env
+ */
+ public static MutableLinkedHashMap fromProperties(String properties) {
+ MutableLinkedHashMap map = Maps.newMutableLinkedMap();
+ String[] rows = properties.split(Const.LF);
+ for (String row : rows) {
+ String key = row.split("=")[0];
+ String value;
+ if (row.length() > key.length()) {
+ value = row.substring(key.length() + 1);
+ } else {
+ value = Strings.EMPTY;
+ }
+ map.put(key, value);
+ }
+ return map;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/utils/AvatarPicHolder.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/utils/AvatarPicHolder.java
new file mode 100644
index 0000000..ca68111
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/utils/AvatarPicHolder.java
@@ -0,0 +1,89 @@
+package cn.orionsec.ops.utils;
+
+import cn.orionsec.kit.lang.utils.Strings;
+import cn.orionsec.kit.lang.utils.codec.Base64s;
+import cn.orionsec.kit.lang.utils.io.FileReaders;
+import cn.orionsec.kit.lang.utils.io.Files1;
+import cn.orionsec.ops.constant.Const;
+import cn.orionsec.ops.constant.system.SystemEnvAttr;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class AvatarPicHolder {
+
+ private AvatarPicHolder() {
+ }
+
+ /**
+ * 获取头像路径
+ *
+ * @param uid uid
+ * @param suffix 后缀
+ * @return path
+ */
+ public static String getPicPath(Long uid, String suffix) {
+ return Const.AVATAR_DIR + "/" + uid + "." + suffix;
+ }
+
+ /**
+ * 创建并获取头像全路径
+ *
+ * @param uid uid
+ * @param suffix 后缀
+ * @return path
+ */
+ public static String touchPicFile(Long uid, String suffix) {
+ String path = Files1.getPath(SystemEnvAttr.PIC_PATH.getValue(), getPicPath(uid, suffix));
+ Files1.touch(path);
+ return path;
+ }
+
+ /**
+ * 删除图片
+ *
+ * @param url url
+ */
+ public static void deletePic(String url) {
+ String path = Files1.getPath(SystemEnvAttr.PIC_PATH.getValue(), url);
+ Files1.delete(path);
+ }
+
+ /**
+ * 获取头像
+ *
+ * @param path path
+ * @return avatar base64
+ */
+ public static String getUserAvatar(String path) {
+ if (isExist(path)) {
+ return getBase64(path);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * 判断是否存在
+ *
+ * @param path path
+ * @return 是否存在
+ */
+ public static boolean isExist(String path) {
+ return Strings.isNotBlank(path) && Files1.isFile(Files1.getPath(SystemEnvAttr.PIC_PATH.getValue(), path));
+ }
+
+ /**
+ * 获取头像 base64
+ *
+ * @param url url
+ * @return base64
+ */
+ public static String getBase64(String url) {
+ String path = Files1.getPath(SystemEnvAttr.PIC_PATH.getValue(), url);
+ if (!Files1.isFile(path)) {
+ return null;
+ }
+ return Base64s.imgEncode(FileReaders.readAllBytes(path), Files1.getSuffix(path));
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/utils/EventLogUtils.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/utils/EventLogUtils.java
new file mode 100644
index 0000000..595aaf7
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/utils/EventLogUtils.java
@@ -0,0 +1,24 @@
+package cn.orionsec.ops.utils;
+
+import cn.orionsec.ops.constant.event.EventKeys;
+
+import java.util.Map;
+
+public class EventLogUtils {
+
+ private EventLogUtils() {
+ }
+
+ /**
+ * 移除内部key
+ *
+ * @param map map
+ */
+ public static void removeInnerKeys(Map map) {
+ map.remove(EventKeys.INNER_USER_ID);
+ map.remove(EventKeys.INNER_USER_NAME);
+ map.remove(EventKeys.INNER_SAVE);
+ map.remove(EventKeys.INNER_TEMPLATE);
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/utils/FileCleaner.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/utils/FileCleaner.java
new file mode 100644
index 0000000..4275a09
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/utils/FileCleaner.java
@@ -0,0 +1,116 @@
+package cn.orionsec.ops.utils;
+
+import cn.orionsec.kit.lang.utils.io.Files1;
+import cn.orionsec.kit.lang.utils.time.Dates;
+import cn.orionsec.ops.constant.Const;
+import cn.orionsec.ops.constant.system.SystemCleanType;
+import cn.orionsec.ops.constant.system.SystemEnvAttr;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.File;
+import java.util.Date;
+import java.util.List;
+
+@Slf4j
+public class FileCleaner {
+
+ private FileCleaner() {
+ }
+
+ /**
+ * 清理所有
+ */
+ public static void cleanAll() {
+ Date threshold = Dates.stream().subDay(Integer.parseInt(SystemEnvAttr.FILE_CLEAN_THRESHOLD.getValue())).get();
+ long thresholdTime = threshold.getTime();
+ log.info("自动清理文件-阈值 {}", Dates.format(threshold));
+ long releasedBytes = 0L;
+ // 清理临时文件
+ releasedBytes += deletePathFiles(thresholdTime, new File(SystemEnvAttr.TEMP_PATH.getValue()));
+ // 日志文件
+ releasedBytes += deletePathFiles(thresholdTime, new File(SystemEnvAttr.LOG_PATH.getValue()));
+ // 交换文件
+ releasedBytes += deletePathFiles(thresholdTime, new File(SystemEnvAttr.SWAP_PATH.getValue()));
+ // 构建产物
+ releasedBytes += deletePathFiles(thresholdTime, new File(SystemEnvAttr.DIST_PATH.getValue()));
+ // 应用仓库 文件太多会 oom
+ // File repoPath = new File(SystemEnvAttr.REPO_PATH.getValue());
+ // List repoPaths = Files1.listFilesFilter(repoPath, (f, n) -> f.isDirectory() && !Const.EVENT.equals(n), false, true);
+ // for (File repo : repoPaths) {
+ // releasedBytes += deletePathFiles(thresholdTime, repo);
+ // }
+ log.info("自动清理文件-释放 {}", Files1.getSize(releasedBytes));
+ }
+
+ /**
+ * 清理目录
+ *
+ * @param cleanType cleanType
+ */
+ public static void cleanDir(SystemCleanType cleanType) {
+ Date threshold = Dates.stream().subDay(Integer.parseInt(SystemEnvAttr.FILE_CLEAN_THRESHOLD.getValue())).get();
+ long thresholdTime = threshold.getTime();
+ long releasedBytes = 0L;
+ log.info("手动清理文件-阈值 {}", Dates.format(threshold));
+ switch (cleanType) {
+ case TEMP_FILE:
+ // 清理临时文件
+ releasedBytes += deletePathFiles(thresholdTime, new File(SystemEnvAttr.TEMP_PATH.getValue()));
+ break;
+ case LOG_FILE:
+ // 日志文件
+ releasedBytes += deletePathFiles(thresholdTime, new File(SystemEnvAttr.LOG_PATH.getValue()));
+ break;
+ case SWAP_FILE:
+ // 交换文件
+ releasedBytes += deletePathFiles(thresholdTime, new File(SystemEnvAttr.SWAP_PATH.getValue()));
+ break;
+ case DIST_FILE:
+ // 构建产物
+ releasedBytes += deletePathFiles(thresholdTime, new File(SystemEnvAttr.DIST_PATH.getValue()));
+ break;
+ case REPO_FILE:
+ // 应用仓库
+ File repoPath = new File(SystemEnvAttr.REPO_PATH.getValue());
+ List repoPaths = Files1.listFilesFilter(repoPath, f -> f.isDirectory() && !Const.EVENT.equals(f.getName()), false, true);
+ for (File repo : repoPaths) {
+ releasedBytes += deletePathFiles(thresholdTime, repo);
+ }
+ break;
+ case SCREEN_FILE:
+ // 录屏文件
+ releasedBytes += deletePathFiles(thresholdTime, new File(SystemEnvAttr.SCREEN_PATH.getValue()));
+ break;
+ default:
+ }
+ log.info("手动清理文件-释放 {}", Files1.getSize(releasedBytes));
+ }
+
+ /**
+ * 删除文件
+ *
+ * @param thresholdTime 阈值
+ * @param path 文件夹
+ * @return size
+ */
+ private static long deletePathFiles(long thresholdTime, File path) {
+ List files = Files1.listFilesFilter(path, p -> checkLessThanThreshold(thresholdTime, p), true, true);
+ long size = files.stream().mapToLong(File::length).sum();
+ files.stream().filter(File::isFile).forEach(Files1::delete);
+ files.stream().filter(File::isDirectory).forEach(Files1::delete);
+ files.clear();
+ return size;
+ }
+
+ /**
+ * 检查文件是否超过阈值
+ *
+ * @param thresholdTime 阈值
+ * @param file 文件
+ * @return 是否超过
+ */
+ private static boolean checkLessThanThreshold(long thresholdTime, File file) {
+ return file.lastModified() <= thresholdTime;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/utils/PathBuilders.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/utils/PathBuilders.java
new file mode 100644
index 0000000..d90d146
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/utils/PathBuilders.java
@@ -0,0 +1,286 @@
+package cn.orionsec.ops.utils;
+
+import cn.orionsec.kit.lang.id.ObjectIds;
+import cn.orionsec.kit.lang.utils.Systems;
+import cn.orionsec.kit.lang.utils.io.Files1;
+import cn.orionsec.kit.lang.utils.time.Dates;
+import cn.orionsec.ops.constant.Const;
+
+import java.util.List;
+
+public class PathBuilders {
+
+ private PathBuilders() {
+ }
+
+ /**
+ * 获取 terminal 录屏路径
+ *
+ * @param userId userId
+ * @param machineId machineId
+ * @return path
+ */
+ public static String getTerminalScreenPath(Long userId, Long machineId) {
+ return Const.TERMINAL_DIR
+ + "/" + userId
+ + "_" + machineId
+ + "_" + Dates.current(Dates.YMD_HMS2)
+ + "." + Const.CAST_SUFFIX;
+ }
+
+ /**
+ * 获取 exec 日志路径
+ *
+ * @param suffix suffix
+ * @param execId execId
+ * @param machineId machineId
+ * @return path
+ */
+ public static String getExecLogPath(String suffix, Long execId, Long machineId) {
+ return Const.EXEC_DIR + suffix
+ + "/" + execId
+ + "_" + machineId
+ + "_" + Dates.current(Dates.YMD_HMS2)
+ + "." + Const.SUFFIX_LOG;
+ }
+
+ /**
+ * 获取应用构建产物文件目录
+ *
+ * @param buildId buildId
+ * @return path
+ */
+ public static String getBuildBundlePath(Long buildId) {
+ return Const.BUILD_DIR + "/" + buildId;
+ }
+
+ /**
+ * 获取应用构建日志文件
+ *
+ * @param buildId buildId
+ * @return path
+ */
+ public static String getBuildLogPath(Long buildId) {
+ return Const.BUILD_DIR
+ + "/" + buildId
+ + "/" + Const.BUILD
+ + "." + Const.SUFFIX_LOG;
+ }
+
+ /**
+ * 获取应用构建操作日志文件
+ *
+ * @param buildId buildId
+ * @return path
+ */
+ public static String getBuildActionLogPath(Long buildId, Long actionId) {
+ return Const.BUILD_DIR
+ + "/" + buildId
+ + "/" + Const.ACTION
+ + "_" + actionId
+ + "." + Const.SUFFIX_LOG;
+ }
+
+ /**
+ * 获取应用发布目标机器日志文件
+ *
+ * @param releaseId releaseId
+ * @param machineId 机器id
+ * @return path
+ */
+ public static String getReleaseMachineLogPath(Long releaseId, Long machineId) {
+ return Const.RELEASE_DIR
+ + "/" + releaseId
+ + Const.RELEASE_MACHINE_PREFIX
+ + "_" + machineId
+ + "." + Const.SUFFIX_LOG;
+ }
+
+ /**
+ * 获取应用发布操作日志文件
+ *
+ * @param releaseId releaseId
+ * @param machineId machineId
+ * @param actionId actionId
+ * @return path
+ */
+ public static String getReleaseActionLogPath(Long releaseId, Long machineId, Long actionId) {
+ return Const.RELEASE_DIR
+ + "/" + releaseId
+ + Const.RELEASE_MACHINE_PREFIX
+ + "_" + machineId
+ + "_" + Const.ACTION
+ + "_" + actionId
+ + "." + Const.SUFFIX_LOG;
+ }
+
+ /**
+ * 获取 release 产物快照文件
+ *
+ * @param releaseId releaseId
+ * @param distPath distPath
+ * @return path
+ */
+ public static String getDistSnapshotPath(Long releaseId, String distPath) {
+ return "/" + releaseId + "_" + Files1.getFileName(distPath);
+ }
+
+ /**
+ * 获取调度任务机器日志文件
+ *
+ * @param taskId taskId
+ * @param recordId recordId
+ * @param machineId machineId
+ * @return path
+ */
+ public static String getSchedulerTaskLogPath(Long taskId, Long recordId, Long machineId) {
+ return Const.TASK_DIR
+ + "/" + taskId
+ + "/" + recordId
+ + "/" + machineId
+ + "." + Const.SUFFIX_LOG;
+ }
+
+
+ /**
+ * 获取 sftp upload 文件路径
+ *
+ * @param fileToken fileToken
+ * @return path
+ */
+ public static String getSftpUploadFilePath(String fileToken) {
+ return Const.UPLOAD_DIR + "/" + fileToken + Const.SWAP_FILE_SUFFIX;
+ }
+
+ /**
+ * 获取 sftp download 文件路径
+ *
+ * @param fileToken fileToken
+ * @return path
+ */
+ public static String getSftpDownloadFilePath(String fileToken) {
+ return Const.DOWNLOAD_DIR + "/" + fileToken + Const.SWAP_FILE_SUFFIX;
+ }
+
+ /**
+ * 获取 sftp package 文件路径
+ *
+ * @param fileToken fileToken
+ * @return path
+ */
+ public static String getSftpPackageFilePath(String fileToken) {
+ return Const.PACKAGE_DIR + "/" + fileToken + "." + Const.SUFFIX_ZIP;
+ }
+
+ /**
+ * 获取导出数据 xlsx 文件路径
+ *
+ * @param userId userId
+ * @param type type
+ * @return path
+ */
+ public static String getExportDataJsonPath(Long userId, Integer type, String password) {
+ return Const.EXPORT_DIR
+ + "/" + type
+ + "/" + Dates.current(Dates.YMD_HMS2)
+ + "-" + userId
+ + "-" + password
+ + "." + Const.SUFFIX_XLSX;
+ }
+
+ /**
+ * 获取导入数据 json 文件路径
+ *
+ * @param userId userId
+ * @param type type
+ * @param token token
+ * @return path
+ */
+ public static String getImportDataJsonPath(Long userId, Integer type, String token) {
+ return Const.IMPORT_DIR
+ + "/" + type
+ + "/" + Dates.current(Dates.YMD_HMS2)
+ + "-" + userId
+ + "-" + token
+ + "." + Const.SUFFIX_JSON;
+ }
+
+ /**
+ * 获取用户根目录
+ *
+ * @param username 用户名
+ * @return 用户目录
+ */
+ public static String getHomePath(String username) {
+ if (Const.ROOT.equals(username)) {
+ return "/" + Const.ROOT;
+ } else {
+ return "/home/" + username;
+ }
+ }
+
+ /**
+ * 获取密钥路径
+ *
+ * @return path
+ */
+ public static String getSecretKeyPath() {
+ return "/" + ObjectIds.nextId() + Const.SECRET_KEY_SUFFIX;
+ }
+
+ /**
+ * 获取宿主机环境目录
+ *
+ * @param path 子目录
+ * @return path
+ */
+ public static String getHostEnvPath(String path) {
+ return Systems.HOME_DIR + "/" + Const.ORION_OPS + "/" + path;
+ }
+
+ /**
+ * 获取 sftp 打包临时目录
+ *
+ * @param username username
+ * @param fileToken fileToken
+ * @param paths paths
+ * @return path
+ */
+ public static String getSftpPackageTempPath(String username, String fileToken, List paths) {
+ return PathBuilders.getHomePath(username)
+ + "/" + Const.ORION_OPS
+ + "/" + Const.PACKAGE
+ + "/" + fileToken
+ + "/" + Files1.getFileName(paths.get(0))
+ + " more files"
+ + "." + Const.SUFFIX_ZIP;
+ }
+
+ /**
+ * 获取插件目录
+ *
+ * @param username username
+ * @return path
+ */
+ public static String getPluginPath(String username) {
+ return PathBuilders.getHomePath(username)
+ + "/" + Const.ORION_OPS
+ + "/" + Const.PLUGINS;
+ }
+
+ /**
+ * 获取安装日志路径
+ *
+ * @param machineId machineId
+ * @param app app
+ * @return path
+ */
+ public static String getInstallLogPath(Long machineId, String app) {
+ return Const.INSTALL_DIR
+ + "/" + app
+ + "/" + machineId
+ + "-" + Dates.current(Dates.YMD_HMS2)
+ + "." + Const.SUFFIX_LOG;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/utils/ResourceLoader.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/utils/ResourceLoader.java
new file mode 100644
index 0000000..d55493e
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/utils/ResourceLoader.java
@@ -0,0 +1,40 @@
+package cn.orionsec.ops.utils;
+
+import cn.orionsec.kit.lang.utils.Exceptions;
+import cn.orionsec.kit.lang.utils.Strings;
+import cn.orionsec.kit.lang.utils.collect.Maps;
+import cn.orionsec.kit.lang.utils.io.Streams;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+import java.util.Objects;
+
+@Slf4j
+public class ResourceLoader {
+
+ /**
+ * key: resource
+ * value: content
+ */
+ private static final Map RESOURCE = Maps.newMap();
+
+ /**
+ * 获取资源
+ *
+ * @param resource resource
+ * @param loader 加载类
+ * @return content
+ */
+ public static String get(String resource, Class> loader) {
+ try (InputStream stream = loader.getResourceAsStream(resource)) {
+ String content = Streams.toString(Objects.requireNonNull(stream));
+ RESOURCE.put(resource, content);
+ return content;
+ } catch (IOException e) {
+ throw Exceptions.notFound(Strings.format("resource not found {} by {}", resource, loader.getName()), e);
+ }
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/utils/Utils.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/utils/Utils.java
new file mode 100644
index 0000000..fa32fe7
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/utils/Utils.java
@@ -0,0 +1,263 @@
+package cn.orionsec.ops.utils;
+
+import cn.orionsec.kit.ext.location.Region;
+import cn.orionsec.kit.ext.location.region.LocationRegions;
+import cn.orionsec.kit.lang.id.UUIds;
+import cn.orionsec.kit.lang.utils.Strings;
+import cn.orionsec.kit.lang.utils.io.Files1;
+import cn.orionsec.kit.lang.utils.net.IPs;
+import cn.orionsec.kit.lang.utils.time.Dates;
+import cn.orionsec.ops.constant.CnConst;
+import cn.orionsec.ops.constant.Const;
+import cn.orionsec.ops.constant.common.StainCode;
+import cn.orionsec.ops.constant.system.SystemEnvAttr;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class Utils {
+
+ private Utils() {
+ }
+
+ /**
+ * 获取随机后缀
+ *
+ * @return suffix
+ */
+ public static String getRandomSuffix() {
+ return UUIds.random32().substring(0, 5).toUpperCase();
+ }
+
+ /**
+ * 获取后缀
+ *
+ * @param symbol symbol
+ * @return suffix
+ */
+ public static String getSymbolSuffix(String symbol) {
+ return " - " + symbol + Strings.SPACE + UUIds.random32().substring(0, 5).toUpperCase();
+ }
+
+ /**
+ * 检查是否是合法 ip 配置行
+ *
+ * @param line line
+ * @return 是否合法
+ */
+ public static boolean validIpLine(String line) {
+ // 普通ip
+ line = line.trim();
+ if (!line.contains(Const.SLASH)) {
+ return IPs.isIpv4(line);
+ }
+ return validIpRange(line);
+ }
+
+ /**
+ * 检查是否为合法 ip 区间
+ *
+ * @param range range
+ * @return 是否合法
+ */
+ public static boolean validIpRange(String range) {
+ // ip区间
+ String[] split = range.split(Const.SLASH);
+ String first = split[0];
+ String last = split[1];
+ if (split.length != 2) {
+ return false;
+ }
+ // 检查第一段
+ if (!IPs.isIpv4(first)) {
+ return false;
+ }
+ // 尾ip
+ if (!last.contains(Const.DOT)) {
+ last = first.substring(0, first.lastIndexOf(Const.DOT)) + Const.DOT + last;
+ }
+ return IPs.isIpv4(last);
+ }
+
+ /**
+ * 检查 ip 是否在范围内
+ *
+ * @param ip ip
+ * @param filter filter
+ * @return 是否在范围内
+ */
+ public static boolean checkIpIn(String ip, String filter) {
+ filter = filter.trim();
+ // 单个ip
+ if (!filter.contains(Const.SLASH)) {
+ return ip.equals(filter);
+ }
+ // ip区间
+ String[] split = filter.split(Const.SLASH);
+ String first = split[0];
+ String last = split[1];
+ // 尾ip
+ if (!last.contains(Const.DOT)) {
+ last = first.substring(0, first.lastIndexOf(Const.DOT)) + Const.DOT + last;
+ }
+ return IPs.ipInRange(first, last, ip);
+ }
+
+ /**
+ * 获取事件仓库路径
+ *
+ * @param id id
+ * @return 路径
+ */
+ public static String getRepositoryEventDir(Long id) {
+ return Files1.getPath(SystemEnvAttr.REPO_PATH.getValue(), Const.EVENT_DIR + "/" + id);
+ }
+
+ /**
+ * 获取时差
+ *
+ * @param ms ms
+ * @return 时差
+ */
+ public static String interval(Long ms) {
+ if (ms == null) {
+ return null;
+ }
+ return Dates.interval(ms, false, "d ", "h ", "m ", "s");
+ }
+
+ /**
+ * 获取 ANSI 高亮颜色行
+ *
+ * @param key key
+ * @param code code
+ * @return 高亮字体
+ * @see StainCode
+ */
+ public static String getStainKeyWords(Object key, int code) {
+ return StainCode.prefix(code) + key + StainCode.SUFFIX;
+ }
+
+ /**
+ * 清除 ANSI 高亮颜色行
+ *
+ * @param s s
+ * @return 清除 ANSI 颜色属性
+ * @see StainCode
+ */
+ public static String cleanStainAnsiCode(String s) {
+ return s.replaceAll("\\u001B\\[\\w{1,3}m", Const.EMPTY);
+ }
+
+ /**
+ * 判断是否为 \n 结尾
+ * 是则返回 \n
+ * 否则返回 \n\n
+ *
+ * @param s s
+ * @return lf
+ */
+ public static String getEndLfWithEof(String s) {
+ return s.endsWith(Const.LF) ? s + Const.LF : s + Const.LF_2;
+ }
+
+ /**
+ * 获取 sftp 压缩命令
+ *
+ * @param zipPath zipPath
+ * @param paths paths
+ * @return zip 命令
+ */
+ public static String getSftpPackageCommand(String zipPath, List paths) {
+ return "mkdir -p " + Files1.getParentPath(zipPath) + " && zip -r \"" + zipPath + "\" "
+ + paths.stream()
+ .map(Files1::getPath)
+ .map(s -> "\"" + s + "\"")
+ .collect(Collectors.joining(Const.SPACE));
+ }
+
+ /**
+ * 清空高亮标签
+ *
+ * @param m m
+ * @return clean
+ */
+ public static String cleanStainTag(String m) {
+ if (Strings.isEmpty(m)) {
+ return m;
+ }
+ return m.replaceAll("", Const.EMPTY)
+ .replaceAll("", Const.EMPTY)
+ .replaceAll("", Const.EMPTY)
+ .replaceAll(" ", Const.EMPTY)
+ .replaceAll("", Const.EMPTY)
+ .replaceAll("", Const.EMPTY)
+ .replaceAll("", Const.EMPTY)
+ .replaceAll(" ", Const.EMPTY)
+ .replaceAll("", Const.EMPTY)
+ .replaceAll(" ", Const.EMPTY);
+ }
+
+ /**
+ * 获取 ip 位置
+ *
+ * @param ip ip
+ * @return ip 位置
+ */
+ public static String getIpLocation(String ip) {
+ if (ip == null) {
+ return CnConst.UNKNOWN;
+ }
+ Region region;
+ try {
+ region = LocationRegions.getRegion(ip, 3);
+ } catch (Exception e) {
+ return CnConst.UNKNOWN;
+ }
+ if (region != null) {
+ String net = region.getNet();
+ String province = region.getProvince();
+ if (net.equals(CnConst.INTRANET_IP)) {
+ return net;
+ }
+ if (province.equals(CnConst.UNKNOWN)) {
+ return province;
+ }
+ StringBuilder location = new StringBuilder()
+ .append(region.getCountry())
+ .append(Const.DASHED)
+ .append(province)
+ .append(Const.DASHED)
+ .append(region.getCity());
+ location.append(" (").append(net).append(')');
+ return location.toString();
+ }
+ return CnConst.UNKNOWN;
+ }
+
+ /**
+ * 转换控制字符 unicode
+ *
+ * @param str str
+ * @return unicode
+ */
+ public static String convertControlUnicode(String str) {
+ char[] chars = str.toCharArray();
+ StringBuilder sb = new StringBuilder();
+ for (char c : chars) {
+ if (c < 32 || c == 34 || c == 92 || c == 127) {
+ sb.append("\\u00");
+ int code = (c & 0xFF);
+ String tmp = Integer.toHexString(code);
+ if (tmp.length() == 1) {
+ sb.append("0");
+ }
+ sb.append(tmp);
+ } else {
+ sb.append(c);
+ }
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/utils/Valid.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/utils/Valid.java
new file mode 100644
index 0000000..cf83b8c
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/utils/Valid.java
@@ -0,0 +1,110 @@
+package cn.orionsec.ops.utils;
+
+import cn.orionsec.kit.lang.define.wrapper.HttpWrapper;
+import cn.orionsec.kit.lang.utils.Arrays1;
+import cn.orionsec.kit.lang.utils.Exceptions;
+import cn.orionsec.kit.lang.utils.Strings;
+import cn.orionsec.kit.lang.utils.io.Files1;
+import cn.orionsec.ops.constant.Const;
+import cn.orionsec.ops.constant.MessageConst;
+import cn.orionsec.ops.constant.system.SystemEnvAttr;
+
+import java.util.Collection;
+
+public class Valid extends cn.orionsec.kit.lang.utils.Valid {
+
+ public static T notNull(T object) {
+ return notNull(object, MessageConst.ABSENT_PARAM);
+ }
+
+ public static String notBlank(String s) {
+ return notBlank(s, MessageConst.ABSENT_PARAM);
+ }
+
+ public static > T notEmpty(T object) {
+ return notEmpty(object, MessageConst.ABSENT_PARAM);
+ }
+
+ public static void eq(Object o1, Object o2) {
+ eq(o1, o2, MessageConst.INVALID_PARAM);
+ }
+
+ public static void allNotNull(Object... objects) {
+ if (objects != null) {
+ for (Object t : objects) {
+ notNull(t, MessageConst.ABSENT_PARAM);
+ }
+ }
+ }
+
+ public static void allNotBlank(String... ss) {
+ if (ss != null) {
+ for (String s : ss) {
+ notBlank(s, MessageConst.ABSENT_PARAM);
+ }
+ }
+ }
+
+ public static boolean isTrue(boolean s) {
+ return isTrue(s, MessageConst.INVALID_PARAM);
+ }
+
+ public static boolean isFalse(boolean s) {
+ return isFalse(s, MessageConst.INVALID_PARAM);
+ }
+
+ public static > T gte(T t1, T t2) {
+ return gte(t1, t2, MessageConst.INVALID_PARAM);
+ }
+
+ @SafeVarargs
+ public static T in(T t, T... ts) {
+ notNull(t);
+ notEmpty(ts);
+ isTrue(Arrays1.contains(ts, t), MessageConst.INVALID_PARAM);
+ return t;
+ }
+
+ public static void isSafe(boolean s) {
+ isTrue(s, MessageConst.UNSAFE_OPERATOR);
+ }
+
+ /**
+ * 检查路径是否合法化 即不包含 ./ ../
+ *
+ * @param path path
+ */
+ public static void checkNormalize(String path) {
+ Valid.notBlank(path);
+ Valid.isTrue(Files1.isNormalize(path), MessageConst.PATH_NOT_NORMALIZE);
+ }
+
+ /**
+ * 检查是否超过文件上传阈值
+ *
+ * @param size size
+ */
+ public static void checkUploadSize(Long size) {
+ Valid.notNull(size);
+ String uploadThreshold = SystemEnvAttr.SFTP_UPLOAD_THRESHOLD.getValue();
+ if (size / Const.BUFFER_KB_1 / Const.BUFFER_KB_1 > Long.parseLong(uploadThreshold)) {
+ throw Exceptions.argument(Strings.format(MessageConst.UPLOAD_TOO_LARGE, uploadThreshold, Files1.getSize(size)));
+ }
+ }
+
+ /**
+ * 检查 api 调用是否成功
+ *
+ * @param wrapper wrapper
+ * @param T
+ * @return value
+ */
+ public static T api(HttpWrapper wrapper) {
+ if (wrapper.isOk()) {
+ return wrapper.getData();
+ } else {
+ throw Exceptions.httpRequest(null, String.valueOf(wrapper.getData()));
+ }
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/utils/ValueMix.java b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/utils/ValueMix.java
new file mode 100644
index 0000000..8ff1d3a
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/main/java/cn/orionsec/ops/utils/ValueMix.java
@@ -0,0 +1,208 @@
+package cn.orionsec.ops.utils;
+
+import cn.orionsec.kit.lang.utils.Arrays1;
+import cn.orionsec.kit.lang.utils.Strings;
+import cn.orionsec.kit.lang.utils.codec.Base62s;
+import cn.orionsec.kit.lang.utils.crypto.Signatures;
+import cn.orionsec.kit.lang.utils.crypto.enums.PaddingMode;
+import cn.orionsec.kit.lang.utils.crypto.enums.WorkingMode;
+import cn.orionsec.kit.lang.utils.crypto.symmetric.EcbSymmetric;
+import cn.orionsec.kit.lang.utils.crypto.symmetric.SymmetricBuilder;
+import cn.orionsec.ops.constant.PropertiesConst;
+
+import java.util.Arrays;
+import java.util.Optional;
+
+public class ValueMix {
+
+ private static final EcbSymmetric ECB = SymmetricBuilder.aes()
+ .workingMode(WorkingMode.ECB)
+ .paddingMode(PaddingMode.PKCS5_PADDING)
+ .generatorSecretKey(PropertiesConst.VALUE_MIX_SECRET_KEY)
+ .buildEcb();
+
+ private ValueMix() {
+ }
+
+ /**
+ * 加密
+ *
+ * @param value 明文
+ * @return 密文
+ */
+ public static String encrypt(String value) {
+ if (value == null) {
+ return null;
+ }
+ try {
+ return ValueMix.ECB.encryptAsString(value);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * 加密
+ *
+ * @param value 明文
+ * @param key key
+ * @return 密文
+ */
+ public static String encrypt(String value, String key) {
+ if (value == null) {
+ return null;
+ }
+ try {
+ return SymmetricBuilder.aes()
+ .workingMode(WorkingMode.ECB)
+ .paddingMode(PaddingMode.PKCS5_PADDING)
+ .generatorSecretKey(key)
+ .buildEcb()
+ .encryptAsString(value);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * 解密
+ *
+ * @param value 密文
+ * @return 明文
+ */
+ public static String decrypt(String value) {
+ if (value == null) {
+ return null;
+ }
+ try {
+ return ECB.decryptAsString(value);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * 解密
+ *
+ * @param value 密文
+ * @param key key
+ * @return 明文
+ */
+ public static String decrypt(String value, String key) {
+ if (value == null) {
+ return null;
+ }
+ try {
+ return SymmetricBuilder.aes()
+ .workingMode(WorkingMode.ECB)
+ .paddingMode(PaddingMode.PKCS5_PADDING)
+ .generatorSecretKey(key)
+ .buildEcb()
+ .decryptAsString(value);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * 明文 -> ecb -> base62 -> 密文
+ *
+ * @param value value
+ * @param key key
+ * @return 密文
+ */
+ public static String base62ecbEnc(String value, String key) {
+ return Optional.ofNullable(value)
+ .map(v -> encrypt(value, key))
+ .map(Base62s::encode)
+ .orElse(null);
+ }
+
+ /**
+ * 密文 -> base62 -> ecb -> 明文
+ *
+ * @param value value
+ * @param key key
+ * @return 明文
+ */
+ public static String base62ecbDec(String value, String key) {
+ return Optional.ofNullable(value)
+ .map(Base62s::decode)
+ .map(v -> decrypt(v, key))
+ .orElse(null);
+ }
+
+ /**
+ * 密码签名
+ *
+ * @param password password
+ * @param salt 盐
+ * @return 密文
+ */
+ public static String encPassword(String password, String salt) {
+ return Signatures.md5(password, salt, 3);
+ }
+
+ /**
+ * 密码验签
+ *
+ * @param password password
+ * @param salt salt
+ * @param sign 密码签名
+ * @return 是否正确
+ */
+ public static boolean validPassword(String password, String salt, String sign) {
+ return sign.equals(Signatures.md5(password, salt, 3));
+ }
+
+ /**
+ * 创建登录token
+ *
+ * @param uid uid
+ * @param timestamp 时间戳
+ * @return token
+ */
+ public static String createLoginToken(Long uid, Long timestamp) {
+ return ValueMix.base62ecbEnc(uid + "_" + timestamp, PropertiesConst.VALUE_MIX_SECRET_KEY);
+ }
+
+ /**
+ * 检查loginToken是否合法
+ *
+ * @param token token
+ * @return true合法
+ */
+ public static boolean validLoginToken(String token) {
+ return ValueMix.base62ecbDec(token, PropertiesConst.VALUE_MIX_SECRET_KEY) != null;
+ }
+
+ /**
+ * 获取loginToken的uid
+ *
+ * @param token token
+ * @return uid
+ */
+ public static Long getLoginTokenUserId(String token) {
+ return Optional.ofNullable(ValueMix.base62ecbDec(token, PropertiesConst.VALUE_MIX_SECRET_KEY))
+ .map(s -> s.split("_"))
+ .map(s -> s[0])
+ .filter(Strings::isInteger)
+ .map(Long::valueOf)
+ .orElse(null);
+ }
+
+ /**
+ * 获取loginToken的信息
+ *
+ * @param token token
+ * @return [uid, loginTimestamp]
+ */
+ public static Long[] getLoginTokenInfo(String token) {
+ return Optional.ofNullable(ValueMix.base62ecbDec(token, PropertiesConst.VALUE_MIX_SECRET_KEY))
+ .map(s -> s.split("_"))
+ .filter(s -> Arrays.stream(s).allMatch(Strings::isInteger))
+ .map(s -> Arrays1.mapper(s, Long[]::new, Long::valueOf))
+ .orElse(null);
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/test/java/cn/orionsec/ops/constant/event/AddLicenseHeader.java b/orion-ops-api/orion-ops-common/src/test/java/cn/orionsec/ops/constant/event/AddLicenseHeader.java
new file mode 100644
index 0000000..f8e22a4
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/test/java/cn/orionsec/ops/constant/event/AddLicenseHeader.java
@@ -0,0 +1,83 @@
+package cn.orionsec.ops.constant.event;
+
+import cn.orionsec.kit.lang.define.StopWatch;
+import cn.orionsec.kit.lang.utils.io.FileReaders;
+import cn.orionsec.kit.lang.utils.io.FileWriters;
+import cn.orionsec.kit.lang.utils.io.Files1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+public class AddLicenseHeader {
+
+ private static final String LICENSE = "/*\n" +
+ " * Copyright (c) 2021 - present Jiahang Li, All rights reserved.\n" +
+ " *\n" +
+ " * https://ops.orionsec.cn\n" +
+ " *\n" +
+ " * Members:\n" +
+ " * Jiahang Li - ljh1553488six@139.com - author\n" +
+ " *\n" +
+ " * Licensed under the Apache License, Version 2.0 (the \"License\");\n" +
+ " * you may not use this file except in compliance with the License.\n" +
+ " * You may obtain a copy of the License at\n" +
+ " *\n" +
+ " * http://www.apache.org/licenses/LICENSE-2.0\n" +
+ " *\n" +
+ " * Unless required by applicable law or agreed to in writing, software\n" +
+ " * distributed under the License is distributed on an \"AS IS\" BASIS,\n" +
+ " * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" +
+ " * See the License for the specific language governing permissions and\n" +
+ " * limitations under the License.\n" +
+ " */";
+
+ private static final String PATH = new File("").getAbsolutePath();
+
+ public static void main(String[] args) {
+ StopWatch sw = StopWatch.begin();
+ // 扫描文件
+ List files = Files1.listFilesFilter(PATH, file -> file.isFile()
+ && (file.getName().endsWith(".java") || file.getName().endsWith(".java.vm"))
+ && !file.getAbsolutePath().contains("generated-sources")
+ && !file.getAbsolutePath().contains("node_modules"), true, false);
+ sw.tag("list");
+ // 添加头
+ files.forEach(AddLicenseHeader::addLicenseToFile);
+ sw.tag(" add");
+ sw.stop();
+ System.out.println();
+ System.out.println(sw);
+ }
+
+ /**
+ * 添加 license
+ *
+ * @param file file
+ */
+ private static void addLicenseToFile(File file) {
+ String path = file.getAbsolutePath().substring(PATH.length());
+ try {
+ String line = FileReaders.readLine(file);
+ if (line != null && line.trim().equals("/*")) {
+ System.out.println("Exists " + path);
+ return;
+ }
+ // 读取原始文件内容
+ byte[] bytes = FileReaders.readAllBytesFast(file);
+ // 在头部添加许可证
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ out.write(LICENSE.getBytes(StandardCharsets.UTF_8));
+ out.write('\n');
+ out.write(new String(bytes).replaceAll("\r\n", "\n").getBytes(StandardCharsets.UTF_8));
+ // 写入
+ FileWriters.writeFast(file, out.toByteArray());
+ System.out.println("Added " + path);
+ } catch (IOException e) {
+ System.err.println("Failed " + path);
+ }
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/test/java/cn/orionsec/ops/constant/event/EventClassifyTest.java b/orion-ops-api/orion-ops-common/src/test/java/cn/orionsec/ops/constant/event/EventClassifyTest.java
new file mode 100644
index 0000000..6275872
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/test/java/cn/orionsec/ops/constant/event/EventClassifyTest.java
@@ -0,0 +1,37 @@
+package cn.orionsec.ops.constant.event;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import cn.orionsec.kit.lang.utils.collect.Maps;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import org.junit.Test;
+
+import java.util.LinkedHashMap;
+
+public class EventClassifyTest {
+
+ @Test
+ public void generatorEnumJson() {
+ EventClassify[] values = EventClassify.values();
+ LinkedHashMap map = Maps.newLinkedMap();
+ for (EventClassify value : values) {
+ map.put(value.name(), new EventClassifyJson(value.getClassify(), value.getLabel()));
+ }
+ System.out.println(JSONArray.toJSONString(map, SerializerFeature.PrettyFormat, SerializerFeature.MapSortField));
+ }
+
+ @Data
+ @AllArgsConstructor
+ static class EventClassifyJson {
+
+ @JSONField(ordinal = 0)
+ private Integer value;
+
+ @JSONField(ordinal = 1)
+ private String label;
+
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/test/java/cn/orionsec/ops/constant/event/EventTypeTest.java b/orion-ops-api/orion-ops-common/src/test/java/cn/orionsec/ops/constant/event/EventTypeTest.java
new file mode 100644
index 0000000..e1c2df1
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/test/java/cn/orionsec/ops/constant/event/EventTypeTest.java
@@ -0,0 +1,40 @@
+package cn.orionsec.ops.constant.event;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import cn.orionsec.kit.lang.utils.collect.Maps;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import org.junit.Test;
+
+import java.util.LinkedHashMap;
+
+public class EventTypeTest {
+
+ @Test
+ public void generatorEnumJson() {
+ EventType[] values = EventType.values();
+ LinkedHashMap map = Maps.newLinkedMap();
+ for (EventType value : values) {
+ map.put(value.name(), new EventTypeTest.EventTypeJson(value.getType(), value.getLabel(), value.getClassify().getClassify()));
+ }
+ System.out.println(JSONArray.toJSONString(map, SerializerFeature.PrettyFormat, SerializerFeature.MapSortField));
+ }
+
+ @Data
+ @AllArgsConstructor
+ static class EventTypeJson {
+
+ @JSONField(ordinal = 0)
+ private Integer value;
+
+ @JSONField(ordinal = 1)
+ private String label;
+
+ @JSONField(ordinal = 2)
+ private Integer classify;
+
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-common/src/test/java/cn/orionsec/ops/constant/event/ReplaceVersion.java b/orion-ops-api/orion-ops-common/src/test/java/cn/orionsec/ops/constant/event/ReplaceVersion.java
new file mode 100644
index 0000000..eb594bf
--- /dev/null
+++ b/orion-ops-api/orion-ops-common/src/test/java/cn/orionsec/ops/constant/event/ReplaceVersion.java
@@ -0,0 +1,103 @@
+package cn.orionsec.ops.constant.event;
+
+import cn.orionsec.kit.lang.utils.io.FileReaders;
+import cn.orionsec.kit.lang.utils.io.FileWriters;
+import cn.orionsec.kit.lang.utils.io.Files1;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.util.function.Function;
+
+public class ReplaceVersion {
+
+ private static final String TARGET_VERSION = "1.3.1";
+
+ private static final String REPLACE_VERSION = "1.3.2";
+
+ private static final String PATH = new File("").getAbsolutePath();
+
+ private static final String[] DOCKER_FILES = new String[]{
+ "docker/push.sh",
+ "docker/adminer/build.sh",
+ "docker/adminer/build.sh",
+ "docker/mysql/build.sh",
+ "docker/redis/build.sh",
+ "docker/service/build.sh",
+ "docker-compose.yml",
+ };
+
+ private static final String[] POM_FILES = new String[]{
+ "orion-ops-api/pom.xml",
+ "orion-ops-api/orion-ops-common/pom.xml",
+ "orion-ops-api/orion-ops-dao/pom.xml",
+ "orion-ops-api/orion-ops-data/pom.xml",
+ "orion-ops-api/orion-ops-mapping/pom.xml",
+ "orion-ops-api/orion-ops-model/pom.xml",
+ "orion-ops-api/orion-ops-runner/pom.xml",
+ "orion-ops-api/orion-ops-service/pom.xml",
+ "orion-ops-api/orion-ops-web/pom.xml",
+ };
+
+ private static final String APPLICATION_PROP_FILE = "orion-ops-api/orion-ops-web/src/main/resources/application.properties";
+
+ private static final String PACKAGE_JSON_FILE = "orion-ops-vue/package.json";
+
+ public static void main(String[] args) {
+ replaceDockerFiles();
+ replacePomFiles();
+ replaceApplicationProp();
+ replacePackageJson();
+ }
+
+ /**
+ * 替换 docker 文件
+ */
+ private static void replaceDockerFiles() {
+ for (String file : DOCKER_FILES) {
+ readAndWrite(file, s -> s.replaceAll(TARGET_VERSION, REPLACE_VERSION));
+ }
+ }
+
+ /**
+ * 替换 pom 文件
+ */
+ private static void replacePomFiles() {
+ for (String file : POM_FILES) {
+ readAndWrite(file, s -> s.replaceAll("" + TARGET_VERSION + " ", "" + REPLACE_VERSION + " "));
+ }
+ }
+
+ /**
+ * 替换 application.properties 文件
+ */
+ private static void replaceApplicationProp() {
+ readAndWrite(APPLICATION_PROP_FILE, s -> s.replaceAll("app.version=" + TARGET_VERSION, "app.version=" + REPLACE_VERSION));
+ }
+
+ /**
+ * 替换 package.json 文件
+ */
+ private static void replacePackageJson() {
+ readAndWrite(PACKAGE_JSON_FILE, s -> s.replaceAll("\"version\": \"" + TARGET_VERSION + "\"", "\"version\": \"" + REPLACE_VERSION + "\""));
+ }
+
+ /**
+ * 读取并且写入
+ *
+ * @param path path
+ * @param mapping mapping
+ */
+ private static void readAndWrite(String path, Function mapping) {
+ String filePath = Files1.getPath(PATH, path);
+ try {
+ // 读取文件内容
+ byte[] bytes = FileReaders.readAllBytesFast(filePath);
+ // 写入文件内容
+ FileWriters.writeFast(filePath, mapping.apply(new String(bytes)).getBytes(StandardCharsets.UTF_8));
+ System.out.println("OK: " + path);
+ } catch (Exception e) {
+ System.err.println("ERR: " + path);
+ }
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-dao/pom.xml b/orion-ops-api/orion-ops-dao/pom.xml
new file mode 100644
index 0000000..eb7a9c3
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/pom.xml
@@ -0,0 +1,68 @@
+
+
+
+ cn.orionsec.ops
+ orion-ops-api
+ 1.3.1
+ ../pom.xml
+
+
+ 4.0.0
+ orion-ops-dao
+ orion-ops-dao
+
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+ io.springfox
+ springfox-swagger2
+
+
+
+
+ org.aspectj
+ aspectjweaver
+
+
+
+
+ com.baomidou
+ mybatis-plus-boot-starter
+
+
+
+
+ com.baomidou
+ mybatis-plus-generator
+
+
+ org.apache.velocity
+ velocity-engine-core
+
+
+
+
+ mysql
+ mysql-connector-java
+ runtime
+
+
+ com.alibaba
+ druid-spring-boot-starter
+
+
+
+
+ cn.orionsec.kit
+ orion-all
+
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/AlarmGroupDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/AlarmGroupDAO.java
new file mode 100644
index 0000000..3f48da9
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/AlarmGroupDAO.java
@@ -0,0 +1,9 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.AlarmGroupDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+
+public interface AlarmGroupDAO extends BaseMapper {
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/AlarmGroupNotifyDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/AlarmGroupNotifyDAO.java
new file mode 100644
index 0000000..a539dc4
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/AlarmGroupNotifyDAO.java
@@ -0,0 +1,9 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.AlarmGroupNotifyDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+
+public interface AlarmGroupNotifyDAO extends BaseMapper {
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/AlarmGroupUserDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/AlarmGroupUserDAO.java
new file mode 100644
index 0000000..079a032
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/AlarmGroupUserDAO.java
@@ -0,0 +1,8 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.AlarmGroupUserDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+public interface AlarmGroupUserDAO extends BaseMapper {
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationActionDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationActionDAO.java
new file mode 100644
index 0000000..8c6c5b6
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationActionDAO.java
@@ -0,0 +1,21 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.ApplicationActionDO;
+import cn.orionsec.ops.entity.dto.ApplicationActionConfigDTO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+public interface ApplicationActionDAO extends BaseMapper {
+
+ /**
+ * 获取应用是否已配置
+ *
+ * @param profileId profileId
+ * @param appIdList appIdList
+ * @return rows
+ */
+ List getAppIsConfig(@Param("profileId") Long profileId, @Param("appIdList") List appIdList);
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationActionLogDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationActionLogDAO.java
new file mode 100644
index 0000000..ebbf01b
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationActionLogDAO.java
@@ -0,0 +1,45 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.ApplicationActionLogDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+public interface ApplicationActionLogDAO extends BaseMapper {
+
+ /**
+ * 通过 id 查询状态信息
+ *
+ * @param id id
+ * @return row
+ */
+ ApplicationActionLogDO selectStatusInfoById(@Param("id") Long id);
+
+ /**
+ * 通过 id 查询状态信息
+ *
+ * @param idList idList
+ * @return rows
+ */
+ List selectStatusInfoByIdList(@Param("idList") List idList);
+
+ /**
+ * 通过 relId 查询状态信息
+ *
+ * @param relId relId
+ * @param stageType stageType
+ * @return rows
+ */
+ List selectStatusInfoByRelId(@Param("relId") Long relId, @Param("stageType") Integer stageType);
+
+ /**
+ * 通过 relId 查询状态信息
+ *
+ * @param relIdList relIdList
+ * @param stageType stageType
+ * @return rows
+ */
+ List selectStatusInfoByRelIdList(@Param("relIdList") List relIdList, @Param("stageType") Integer stageType);
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationBuildDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationBuildDAO.java
new file mode 100644
index 0000000..446852d
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationBuildDAO.java
@@ -0,0 +1,94 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.ApplicationBuildDO;
+import cn.orionsec.ops.entity.dto.ApplicationBuildStatisticsDTO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Date;
+import java.util.List;
+
+public interface ApplicationBuildDAO extends BaseMapper {
+
+ /**
+ * 通过 id 查询状态
+ *
+ * @param id id
+ * @return status
+ */
+ Integer selectStatusById(@Param("id") Long id);
+
+ /**
+ * 通过 id 查询状态信息
+ *
+ * @param id id
+ * @return row
+ */
+ ApplicationBuildDO selectStatusInfoById(@Param("id") Long id);
+
+ /**
+ * 通过 id 查询状态信息
+ *
+ * @param idList idList
+ * @return rows
+ */
+ List selectStatusInfoByIdList(@Param("idList") List idList);
+
+ /**
+ * 查询上一次构建分支
+ *
+ * @param appId appId
+ * @param profileId profileId
+ * @param repoId repoId
+ * @return branch
+ */
+ String selectLastBuildBranch(@Param("appId") Long appId, @Param("profileId") Long profileId, @Param("repoId") Long repoId);
+
+ /**
+ * 查询构建序列
+ *
+ * @param id id
+ * @return seq
+ */
+ Integer selectBuildSeq(@Param("id") Long id);
+
+ /**
+ * 查询构建发布列表
+ *
+ * @param appId appId
+ * @param profileId profileId
+ * @param limit limit
+ * @return rows
+ */
+ List selectBuildReleaseList(@Param("appId") Long appId, @Param("profileId") Long profileId, @Param("limit") Integer limit);
+
+ /**
+ * 查询构建发布列表
+ *
+ * @param appIdList appIdList
+ * @param profileId profileId
+ * @return rows
+ */
+ List selectBuildReleaseGroupList(@Param("appIdList") List appIdList, @Param("profileId") Long profileId);
+
+ /**
+ * 获取构建统计
+ *
+ * @param appId appId
+ * @param profileId profileId
+ * @param rangeStartDate rangeStartDate
+ * @return 统计信息
+ */
+ ApplicationBuildStatisticsDTO getBuildStatistics(@Param("appId") Long appId, @Param("profileId") Long profileId, @Param("rangeStartDate") Date rangeStartDate);
+
+ /**
+ * 获取构建时间线统计
+ *
+ * @param appId appId
+ * @param profileId profileId
+ * @param rangeStartDate rangeStartDate
+ * @return 时间线统计信息
+ */
+ List getBuildDateStatistics(@Param("appId") Long appId, @Param("profileId") Long profileId, @Param("rangeStartDate") Date rangeStartDate);
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationEnvDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationEnvDAO.java
new file mode 100644
index 0000000..c07db5b
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationEnvDAO.java
@@ -0,0 +1,28 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.ApplicationEnvDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+
+public interface ApplicationEnvDAO extends BaseMapper {
+
+ /**
+ * 查询一条数据
+ *
+ * @param appId appId
+ * @param profileId profileId
+ * @param key key
+ * @return env
+ */
+ ApplicationEnvDO selectOneRel(@Param("appId") Long appId, @Param("profileId") Long profileId, @Param("key") String key);
+
+ /**
+ * 设置删除
+ *
+ * @param id id
+ * @param deleted deleted
+ * @return effect
+ */
+ Integer setDeleted(@Param("id") Long id, @Param("deleted") Integer deleted);
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationInfoDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationInfoDAO.java
new file mode 100644
index 0000000..19ce651
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationInfoDAO.java
@@ -0,0 +1,43 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.ApplicationInfoDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+public interface ApplicationInfoDAO extends BaseMapper {
+
+ /**
+ * 获取仓库数量
+ *
+ * @param repoId repoId
+ * @return count
+ */
+ Integer selectRepoCount(@Param("repoId") Long repoId);
+
+ /**
+ * 清空仓库
+ *
+ * @param repoId repoId
+ * @return effect
+ */
+ Integer cleanRepoCount(@Param("repoId") Long repoId);
+
+ /**
+ * 查询名称
+ *
+ * @param id id
+ * @return name
+ */
+ String selectNameById(@Param("id") Long id);
+
+ /**
+ * 查询名称
+ *
+ * @param idList idList
+ * @return name
+ */
+ List selectNameByIdList(@Param("idList") List idList);
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationMachineDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationMachineDAO.java
new file mode 100644
index 0000000..e83dcf8
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationMachineDAO.java
@@ -0,0 +1,16 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.ApplicationMachineDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+public interface ApplicationMachineDAO extends BaseMapper {
+
+ /**
+ * 更新版本
+ *
+ * @param update update
+ * @return effect
+ */
+ Integer updateAppVersion(ApplicationMachineDO update);
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationPipelineDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationPipelineDAO.java
new file mode 100644
index 0000000..fe4fb4e
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationPipelineDAO.java
@@ -0,0 +1,8 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.ApplicationPipelineDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+public interface ApplicationPipelineDAO extends BaseMapper {
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationPipelineDetailDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationPipelineDetailDAO.java
new file mode 100644
index 0000000..7228fdf
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationPipelineDetailDAO.java
@@ -0,0 +1,8 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.ApplicationPipelineDetailDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+public interface ApplicationPipelineDetailDAO extends BaseMapper {
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationPipelineTaskDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationPipelineTaskDAO.java
new file mode 100644
index 0000000..bdd83fc
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationPipelineTaskDAO.java
@@ -0,0 +1,55 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.ApplicationPipelineTaskDO;
+import cn.orionsec.ops.entity.dto.ApplicationPipelineTaskStatisticsDTO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Date;
+import java.util.List;
+
+public interface ApplicationPipelineTaskDAO extends BaseMapper {
+
+ /**
+ * 设置定时执行时间为空
+ *
+ * @param id id
+ * @return effect
+ */
+ Integer setTimedExecTimeNull(@Param("id") Long id);
+
+ /**
+ * 查询任务状态
+ *
+ * @param id id
+ * @return row
+ */
+ ApplicationPipelineTaskDO selectStatusById(@Param("id") Long id);
+
+ /**
+ * 查询任务状态
+ *
+ * @param idList idList
+ * @return rows
+ */
+ List selectStatusByIdList(@Param("idList") List idList);
+
+ /**
+ * 获取流水线任务统计
+ *
+ * @param pipelineId pipelineId
+ * @param rangeStartDate rangeStartDate
+ * @return 统计信息
+ */
+ ApplicationPipelineTaskStatisticsDTO getPipelineTaskStatistics(@Param("pipelineId") Long pipelineId, @Param("rangeStartDate") Date rangeStartDate);
+
+ /**
+ * 获取流水线任务时间线统计
+ *
+ * @param pipelineId pipelineId
+ * @param rangeStartDate rangeStartDate
+ * @return 时间线统计信息
+ */
+ List getPipelineTaskDateStatistics(@Param("pipelineId") Long pipelineId, @Param("rangeStartDate") Date rangeStartDate);
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationPipelineTaskDetailDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationPipelineTaskDetailDAO.java
new file mode 100644
index 0000000..9d0d455
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationPipelineTaskDetailDAO.java
@@ -0,0 +1,27 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.ApplicationPipelineTaskDetailDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+public interface ApplicationPipelineTaskDetailDAO extends BaseMapper {
+
+ /**
+ * 查询任务详情状态
+ *
+ * @param taskId taskId
+ * @return rows
+ */
+ List selectStatusByTaskId(@Param("taskId") Long taskId);
+
+ /**
+ * 查询任务详情状态
+ *
+ * @param idList idList
+ * @return rows
+ */
+ List selectStatusByIdList(@Param("idList") List idList);
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationPipelineTaskLogDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationPipelineTaskLogDAO.java
new file mode 100644
index 0000000..99ff5e1
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationPipelineTaskLogDAO.java
@@ -0,0 +1,8 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.ApplicationPipelineTaskLogDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+public interface ApplicationPipelineTaskLogDAO extends BaseMapper {
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationProfileDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationProfileDAO.java
new file mode 100644
index 0000000..d9ed63d
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationProfileDAO.java
@@ -0,0 +1,8 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.ApplicationProfileDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+public interface ApplicationProfileDAO extends BaseMapper {
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationReleaseDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationReleaseDAO.java
new file mode 100644
index 0000000..1a15b03
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationReleaseDAO.java
@@ -0,0 +1,57 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.ApplicationReleaseDO;
+import cn.orionsec.ops.entity.dto.ApplicationReleaseStatisticsDTO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Date;
+import java.util.List;
+
+public interface ApplicationReleaseDAO extends BaseMapper {
+
+ /**
+ * 查询状态
+ *
+ * @param id id
+ * @return row
+ */
+ ApplicationReleaseDO selectStatusById(@Param("id") Long id);
+
+ /**
+ * 查询状态列表
+ *
+ * @param idList idList
+ * @return rows
+ */
+ List selectStatusByIdList(@Param("idList") List idList);
+
+ /**
+ * 设置定时时间为 null
+ *
+ * @param id id
+ * @return effect
+ */
+ Integer setTimedReleaseTimeNull(@Param("id") Long id);
+
+ /**
+ * 获取发布统计
+ *
+ * @param appId appId
+ * @param profileId profileId
+ * @param rangeStartDate rangeStartDate
+ * @return 统计信息
+ */
+ ApplicationReleaseStatisticsDTO getReleaseStatistics(@Param("appId") Long appId, @Param("profileId") Long profileId, @Param("rangeStartDate") Date rangeStartDate);
+
+ /**
+ * 获取发布时间线统计
+ *
+ * @param appId appId
+ * @param profileId profileId
+ * @param rangeStartDate rangeStartDate
+ * @return 时间线统计信息
+ */
+ List getReleaseDateStatistics(@Param("appId") Long appId, @Param("profileId") Long profileId, @Param("rangeStartDate") Date rangeStartDate);
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationReleaseMachineDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationReleaseMachineDAO.java
new file mode 100644
index 0000000..24daf9a
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationReleaseMachineDAO.java
@@ -0,0 +1,43 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.ApplicationReleaseMachineDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+public interface ApplicationReleaseMachineDAO extends BaseMapper {
+
+ /**
+ * 查询发布机器状态
+ *
+ * @param releaseId releaseId
+ * @return rows
+ */
+ List selectStatusByReleaseId(@Param("releaseId") Long releaseId);
+
+ /**
+ * 查询发布机器状态
+ *
+ * @param releaseIdList releaseIdList
+ * @return rows
+ */
+ List selectStatusByReleaseIdList(@Param("releaseIdList") List releaseIdList);
+
+ /**
+ * 查询发布机器状态
+ *
+ * @param id id
+ * @return row
+ */
+ ApplicationReleaseMachineDO selectStatusById(@Param("id") Long id);
+
+ /**
+ * 查询发布机器状态
+ *
+ * @param idList idList
+ * @return rows
+ */
+ List selectStatusByIdList(@Param("idList") List idList);
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationRepositoryDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationRepositoryDAO.java
new file mode 100644
index 0000000..32ddd70
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/ApplicationRepositoryDAO.java
@@ -0,0 +1,27 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.ApplicationRepositoryDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+public interface ApplicationRepositoryDAO extends BaseMapper {
+
+ /**
+ * 通过id查询名称
+ *
+ * @param idList idList
+ * @return rows
+ */
+ List selectNameByIdList(@Param("idList") List idList);
+
+ /**
+ * 通过名称查询id
+ *
+ * @param nameList nameList
+ * @return rows
+ */
+ List selectIdByNameList(@Param("nameList") List nameList);
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/CommandExecDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/CommandExecDAO.java
new file mode 100644
index 0000000..6937de8
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/CommandExecDAO.java
@@ -0,0 +1,17 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.CommandExecDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+
+public interface CommandExecDAO extends BaseMapper {
+
+ /**
+ * 通过 id 查询 status
+ *
+ * @param id id
+ * @return status
+ */
+ CommandExecDO selectStatusById(@Param("id") Long id);
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/CommandTemplateDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/CommandTemplateDAO.java
new file mode 100644
index 0000000..fadac4f
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/CommandTemplateDAO.java
@@ -0,0 +1,8 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.CommandTemplateDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+public interface CommandTemplateDAO extends BaseMapper {
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/FileTailListDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/FileTailListDAO.java
new file mode 100644
index 0000000..7f32a0b
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/FileTailListDAO.java
@@ -0,0 +1,8 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.FileTailListDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+public interface FileTailListDAO extends BaseMapper {
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/FileTransferLogDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/FileTransferLogDAO.java
new file mode 100644
index 0000000..06e0369
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/FileTransferLogDAO.java
@@ -0,0 +1,8 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.FileTransferLogDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+public interface FileTransferLogDAO extends BaseMapper {
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/HistoryValueSnapshotDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/HistoryValueSnapshotDAO.java
new file mode 100644
index 0000000..243484e
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/HistoryValueSnapshotDAO.java
@@ -0,0 +1,8 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.HistoryValueSnapshotDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+public interface HistoryValueSnapshotDAO extends BaseMapper {
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineAlarmConfigDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineAlarmConfigDAO.java
new file mode 100644
index 0000000..df2dd34
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineAlarmConfigDAO.java
@@ -0,0 +1,8 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.MachineAlarmConfigDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+public interface MachineAlarmConfigDAO extends BaseMapper {
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineAlarmGroupDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineAlarmGroupDAO.java
new file mode 100644
index 0000000..8d90f69
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineAlarmGroupDAO.java
@@ -0,0 +1,8 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.MachineAlarmGroupDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+public interface MachineAlarmGroupDAO extends BaseMapper {
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineAlarmHistoryDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineAlarmHistoryDAO.java
new file mode 100644
index 0000000..5b465fc
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineAlarmHistoryDAO.java
@@ -0,0 +1,8 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.MachineAlarmHistoryDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+public interface MachineAlarmHistoryDAO extends BaseMapper {
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineEnvDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineEnvDAO.java
new file mode 100644
index 0000000..c173bfb
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineEnvDAO.java
@@ -0,0 +1,27 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.MachineEnvDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+
+public interface MachineEnvDAO extends BaseMapper {
+
+ /**
+ * 查询一条数据
+ *
+ * @param machineId machineId
+ * @param key key
+ * @return env
+ */
+ MachineEnvDO selectOneRel(@Param("machineId") Long machineId, @Param("key") String key);
+
+ /**
+ * 设置删除
+ *
+ * @param id id
+ * @param deleted deleted
+ * @return effect
+ */
+ Integer setDeleted(@Param("id") Long id, @Param("deleted") Integer deleted);
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineGroupDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineGroupDAO.java
new file mode 100644
index 0000000..000fceb
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineGroupDAO.java
@@ -0,0 +1,26 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.MachineGroupDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+
+public interface MachineGroupDAO extends BaseMapper {
+
+ /**
+ * 增加排序值
+ *
+ * @param parentId parentId
+ * @param greaterSort > sort
+ * @return effect
+ */
+ Integer incrementSort(@Param("parentId") Long parentId, @Param("greaterSort") Integer greaterSort);
+
+ /**
+ * 增加最大 sort
+ *
+ * @param parentId parentId
+ * @return sort
+ */
+ Integer getMaxSort(@Param("parentId") Long parentId);
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineGroupRelDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineGroupRelDAO.java
new file mode 100644
index 0000000..c0c217d
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineGroupRelDAO.java
@@ -0,0 +1,8 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.MachineGroupRelDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+public interface MachineGroupRelDAO extends BaseMapper {
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineInfoDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineInfoDAO.java
new file mode 100644
index 0000000..766d6c7
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineInfoDAO.java
@@ -0,0 +1,58 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.MachineInfoDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+public interface MachineInfoDAO extends BaseMapper {
+
+ /**
+ * 设置id
+ *
+ * @param oldId 原id
+ * @param newId 新id
+ */
+ void setId(@Param("oldId") Long oldId, @Param("newId") Long newId);
+
+ /**
+ * 设置proxyId为null
+ *
+ * @param proxyId proxyId
+ */
+ void setProxyIdWithNull(@Param("proxyId") Long proxyId);
+
+ /**
+ * 通过host查询id
+ *
+ * @param host host
+ * @return rows
+ */
+ List selectIdByHost(@Param("host") String host);
+
+ /**
+ * 查询机器名称
+ *
+ * @param id id
+ * @return name
+ */
+ String selectMachineName(@Param("id") Long id);
+
+ /**
+ * 查询机器名称
+ *
+ * @param idList idList
+ * @return rows
+ */
+ List selectNameByIdList(@Param("idList") List idList);
+
+ /**
+ * 查询机器id
+ *
+ * @param tagList tagList
+ * @return rows
+ */
+ List selectIdByTagList(@Param("tagList") List tagList);
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineMonitorDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineMonitorDAO.java
new file mode 100644
index 0000000..c172c8a
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineMonitorDAO.java
@@ -0,0 +1,30 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.MachineMonitorDO;
+import cn.orionsec.ops.entity.dto.MachineMonitorDTO;
+import cn.orionsec.ops.entity.query.MachineMonitorQuery;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+public interface MachineMonitorDAO extends BaseMapper {
+
+ /**
+ * 查询列表
+ *
+ * @param query query
+ * @param last last sql
+ * @return rows
+ */
+ List selectMonitorList(@Param("query") MachineMonitorQuery query, @Param("last") String last);
+
+ /**
+ * 查询条数
+ *
+ * @param query query
+ * @return count
+ */
+ Integer selectMonitorCount(@Param("query") MachineMonitorQuery query);
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineProxyDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineProxyDAO.java
new file mode 100644
index 0000000..18c6f91
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineProxyDAO.java
@@ -0,0 +1,8 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.MachineProxyDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+public interface MachineProxyDAO extends BaseMapper {
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineSecretKeyDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineSecretKeyDAO.java
new file mode 100644
index 0000000..c904ae1
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineSecretKeyDAO.java
@@ -0,0 +1,19 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.MachineSecretKeyDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+public interface MachineSecretKeyDAO extends BaseMapper {
+
+ /**
+ * 通过名称查询id
+ *
+ * @param nameList nameList
+ * @return rows
+ */
+ List selectIdByNameList(@Param("nameList") List nameList);
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineTerminalDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineTerminalDAO.java
new file mode 100644
index 0000000..407f249
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineTerminalDAO.java
@@ -0,0 +1,8 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.MachineTerminalDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+public interface MachineTerminalDAO extends BaseMapper {
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineTerminalLogDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineTerminalLogDAO.java
new file mode 100644
index 0000000..3e04af1
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/MachineTerminalLogDAO.java
@@ -0,0 +1,8 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.MachineTerminalLogDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+public interface MachineTerminalLogDAO extends BaseMapper {
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/SchedulerTaskDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/SchedulerTaskDAO.java
new file mode 100644
index 0000000..49bfb59
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/SchedulerTaskDAO.java
@@ -0,0 +1,8 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.SchedulerTaskDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+public interface SchedulerTaskDAO extends BaseMapper {
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/SchedulerTaskMachineDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/SchedulerTaskMachineDAO.java
new file mode 100644
index 0000000..82333a1
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/SchedulerTaskMachineDAO.java
@@ -0,0 +1,8 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.SchedulerTaskMachineDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+public interface SchedulerTaskMachineDAO extends BaseMapper {
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/SchedulerTaskMachineRecordDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/SchedulerTaskMachineRecordDAO.java
new file mode 100644
index 0000000..de389c7
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/SchedulerTaskMachineRecordDAO.java
@@ -0,0 +1,43 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.SchedulerTaskMachineRecordDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+public interface SchedulerTaskMachineRecordDAO extends BaseMapper {
+
+ /**
+ * 通过 recordId 查询状态
+ *
+ * @param recordId recordId
+ * @return rows
+ */
+ List selectStatusByRecordId(@Param("recordId") Long recordId);
+
+ /**
+ * 通过 idList 查询状态
+ *
+ * @param idList idList
+ * @return rows
+ */
+ List selectStatusByIdList(@Param("idList") List idList);
+
+ /**
+ * 通过 recordIdList 查询状态
+ *
+ * @param recordIdList recordIdList
+ * @return rows
+ */
+ List selectStatusByRecordIdList(@Param("recordIdList") List recordIdList);
+
+ /**
+ * 通过 recordIdList 删除明细
+ *
+ * @param recordIdList recordIdList
+ * @return effect
+ */
+ Integer deleteByRecordIdList(@Param("recordIdList") List recordIdList);
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/SchedulerTaskRecordDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/SchedulerTaskRecordDAO.java
new file mode 100644
index 0000000..9ad6803
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/SchedulerTaskRecordDAO.java
@@ -0,0 +1,47 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.SchedulerTaskRecordDO;
+import cn.orionsec.ops.entity.dto.SchedulerTaskRecordStatisticsDTO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Date;
+import java.util.List;
+
+public interface SchedulerTaskRecordDAO extends BaseMapper {
+
+ /**
+ * 查询任务状态
+ *
+ * @param idList idList
+ * @return rows
+ */
+ List selectTaskStatusByIdList(@Param("idList") List idList);
+
+ /**
+ * 获取调度任务统计
+ *
+ * @param taskId taskId
+ * @param rangeStartDate 统计开始时间
+ * @return 统计信息
+ */
+ SchedulerTaskRecordStatisticsDTO getTaskRecordStatistics(@Param("taskId") Long taskId, @Param("rangeStartDate") Date rangeStartDate);
+
+ /**
+ * 获取调度任务机器统计
+ *
+ * @param taskId taskId
+ * @return 统计信息
+ */
+ List getTaskMachineRecordStatistics(@Param("taskId") Long taskId);
+
+ /**
+ * 获取调度任务时间线统计
+ *
+ * @param taskId taskId
+ * @param rangeStartDate 统计开始时间
+ * @return 统计信息
+ */
+ List getTaskRecordDateStatistics(@Param("taskId") Long taskId, @Param("rangeStartDate") Date rangeStartDate);
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/SystemEnvDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/SystemEnvDAO.java
new file mode 100644
index 0000000..6e478cf
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/SystemEnvDAO.java
@@ -0,0 +1,26 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.SystemEnvDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+
+public interface SystemEnvDAO extends BaseMapper {
+
+ /**
+ * 查询一条数据
+ *
+ * @param key key
+ * @return env
+ */
+ SystemEnvDO selectOneRel(@Param("key") String key);
+
+ /**
+ * 设置删除
+ *
+ * @param id id
+ * @param deleted deleted
+ * @return effect
+ */
+ Integer setDeleted(@Param("id") Long id, @Param("deleted") Integer deleted);
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/UserEventLogDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/UserEventLogDAO.java
new file mode 100644
index 0000000..54ecc8f
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/UserEventLogDAO.java
@@ -0,0 +1,8 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.UserEventLogDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+public interface UserEventLogDAO extends BaseMapper {
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/UserInfoDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/UserInfoDAO.java
new file mode 100644
index 0000000..3b535f1
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/UserInfoDAO.java
@@ -0,0 +1,17 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.UserInfoDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+
+public interface UserInfoDAO extends BaseMapper {
+
+ /**
+ * 更新最后登录时间
+ *
+ * @param userId userId
+ * @return effect
+ */
+ Integer updateLastLoginTime(@Param("userId") Long userId);
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/WebSideMessageDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/WebSideMessageDAO.java
new file mode 100644
index 0000000..430093f
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/WebSideMessageDAO.java
@@ -0,0 +1,8 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.WebSideMessageDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+public interface WebSideMessageDAO extends BaseMapper {
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/WebhookConfigDAO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/WebhookConfigDAO.java
new file mode 100644
index 0000000..1585a00
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/dao/WebhookConfigDAO.java
@@ -0,0 +1,8 @@
+package cn.orionsec.ops.dao;
+
+import cn.orionsec.ops.entity.domain.WebhookConfigDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+public interface WebhookConfigDAO extends BaseMapper {
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/AlarmGroupDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/AlarmGroupDO.java
new file mode 100644
index 0000000..8e7a7b9
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/AlarmGroupDO.java
@@ -0,0 +1,45 @@
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@TableName("alarm_group")
+@ApiModel(value = "AlarmGroupDO对象", description = "报警组")
+public class AlarmGroupDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "报警组名称")
+ @TableField("group_name")
+ private String groupName;
+
+ @ApiModelProperty(value = "报警组描述")
+ @TableField("group_description")
+ private String groupDescription;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/AlarmGroupNotifyDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/AlarmGroupNotifyDO.java
new file mode 100644
index 0000000..25de469
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/AlarmGroupNotifyDO.java
@@ -0,0 +1,48 @@
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@TableName("alarm_group_notify")
+@ApiModel(value = "AlarmGroupNotifyDO对象", description = "报警组通知方式")
+public class AlarmGroupNotifyDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "报警组id")
+ @TableField("group_id")
+ private Long groupId;
+
+ @ApiModelProperty(value = "通知id")
+ @TableField("notify_id")
+ private Long notifyId;
+
+ @ApiModelProperty(value = "通知类型 10 webhook")
+ @TableField("notify_type")
+ private Integer notifyType;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/AlarmGroupUserDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/AlarmGroupUserDO.java
new file mode 100644
index 0000000..35f6c7c
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/AlarmGroupUserDO.java
@@ -0,0 +1,48 @@
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@TableName("alarm_group_user")
+@ApiModel(value = "AlarmGroupUserDO对象", description = "报警组成员")
+public class AlarmGroupUserDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "报警组id")
+ @TableField("group_id")
+ private Long groupId;
+
+ @ApiModelProperty(value = "报警组成员id")
+ @TableField("user_id")
+ private Long userId;
+
+ @ApiModelProperty(value = "报警组成员用户名")
+ @TableField("username")
+ private String username;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationActionDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationActionDO.java
new file mode 100644
index 0000000..080643b
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationActionDO.java
@@ -0,0 +1,67 @@
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "应用发布执行块")
+@TableName("application_action")
+@SuppressWarnings("ALL")
+public class ApplicationActionDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "appId")
+ @TableField("app_id")
+ private Long appId;
+
+ @ApiModelProperty(value = "profileId")
+ @TableField("profile_id")
+ private Long profileId;
+
+ @ApiModelProperty(value = "名称")
+ @TableField("action_name")
+ private String actionName;
+
+ /**
+ * @see cn.orionsec.ops.constant.app.ActionType
+ */
+ @ApiModelProperty(value = "类型")
+ @TableField("action_type")
+ private Integer actionType;
+
+ /**
+ * @see cn.orionsec.ops.constant.app.StageType
+ */
+ @ApiModelProperty(value = "阶段类型")
+ @TableField("stage_type")
+ private Integer stageType;
+
+ @ApiModelProperty(value = "执行命令")
+ @TableField("action_command")
+ private String actionCommand;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationActionLogDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationActionLogDO.java
new file mode 100644
index 0000000..ba6eb9b
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationActionLogDO.java
@@ -0,0 +1,94 @@
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "应用操作日志")
+@TableName("application_action_log")
+@SuppressWarnings("ALL")
+public class ApplicationActionLogDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ /**
+ * @see cn.orionsec.ops.constant.app.StageType
+ */
+ @ApiModelProperty(value = "阶段类型 10构建 20发布")
+ @TableField("stage_type")
+ private Integer stageType;
+
+ @ApiModelProperty(value = "引用id 构建id 发布机器id")
+ @TableField("rel_id")
+ private Long relId;
+
+ @ApiModelProperty(value = "执行机器id")
+ @TableField("machine_id")
+ private Long machineId;
+
+ @ApiModelProperty(value = "操作id")
+ @TableField("action_id")
+ private Long actionId;
+
+ @ApiModelProperty(value = "操作名称")
+ @TableField("action_name")
+ private String actionName;
+
+ /**
+ * @see cn.orionsec.ops.constant.app.ActionType
+ */
+ @ApiModelProperty(value = "操作类型")
+ @TableField("action_type")
+ private Integer actionType;
+
+ @ApiModelProperty(value = "操作命令")
+ @TableField("action_command")
+ private String actionCommand;
+
+ @ApiModelProperty(value = "操作日志路径")
+ @TableField("log_path")
+ private String logPath;
+
+ /**
+ * @see cn.orionsec.ops.constant.app.ActionStatus
+ */
+ @ApiModelProperty(value = "状态 10未开始 20进行中 30已完成 40执行失败 50已跳过 60已取消")
+ @TableField("run_status")
+ private Integer runStatus;
+
+ @ApiModelProperty(value = "退出码")
+ @TableField("exit_code")
+ private Integer exitCode;
+
+ @ApiModelProperty(value = "开始时间")
+ @TableField("start_time")
+ private Date startTime;
+
+ @ApiModelProperty(value = "结束时间")
+ @TableField("end_time")
+ private Date endTime;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationBuildDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationBuildDO.java
new file mode 100644
index 0000000..67e46dc
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationBuildDO.java
@@ -0,0 +1,112 @@
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "应用构建")
+@TableName("application_build")
+@SuppressWarnings("ALL")
+public class ApplicationBuildDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "应用id")
+ @TableField("app_id")
+ private Long appId;
+
+ @ApiModelProperty(value = "应用名称")
+ @TableField("app_name")
+ private String appName;
+
+ @ApiModelProperty(value = "应用唯一标识")
+ @TableField("app_tag")
+ private String appTag;
+
+ @ApiModelProperty(value = "环境id")
+ @TableField("profile_id")
+ private Long profileId;
+
+ @ApiModelProperty(value = "环境名称")
+ @TableField("profile_name")
+ private String profileName;
+
+ @ApiModelProperty(value = "环境唯一标识")
+ @TableField("profile_tag")
+ private String profileTag;
+
+ @ApiModelProperty(value = "构建序列")
+ @TableField("build_seq")
+ private Integer buildSeq;
+
+ @ApiModelProperty(value = "构建分支")
+ @TableField("branch_name")
+ private String branchName;
+
+ @ApiModelProperty(value = "构建提交id")
+ @TableField("commit_id")
+ private String commitId;
+
+ @ApiModelProperty(value = "应用版本仓库id")
+ @TableField("repo_id")
+ private Long repoId;
+
+ @ApiModelProperty(value = "构建日志路径")
+ @TableField("log_path")
+ private String logPath;
+
+ @ApiModelProperty(value = "构建产物文件")
+ @TableField("bundle_path")
+ private String bundlePath;
+
+ /**
+ * @see cn.orionsec.ops.constant.app.BuildStatus
+ */
+ @ApiModelProperty(value = "状态 10未开始 20执行中 30已完成 40执行失败 50已取消")
+ @TableField("build_status")
+ private Integer buildStatus;
+
+ @ApiModelProperty(value = "描述")
+ @TableField("description")
+ private String description;
+
+ @ApiModelProperty(value = "创建人id")
+ @TableField("create_user_id")
+ private Long createUserId;
+
+ @ApiModelProperty(value = "创建人名称")
+ @TableField("create_user_name")
+ private String createUserName;
+
+ @ApiModelProperty(value = "构建开始时间")
+ @TableField("build_start_time")
+ private Date buildStartTime;
+
+ @ApiModelProperty(value = "构建结束时间")
+ @TableField("build_end_time")
+ private Date buildEndTime;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationEnvDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationEnvDO.java
new file mode 100644
index 0000000..2dfae7c
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationEnvDO.java
@@ -0,0 +1,65 @@
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "应用环境变量")
+@TableName("application_env")
+@SuppressWarnings("ALL")
+public class ApplicationEnvDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "应用id")
+ @TableField("app_id")
+ private Long appId;
+
+ @ApiModelProperty(value = "环境id")
+ @TableField("profile_id")
+ private Long profileId;
+
+ @ApiModelProperty(value = "key")
+ @TableField("attr_key")
+ private String attrKey;
+
+ @ApiModelProperty(value = "value")
+ @TableField("attr_value")
+ private String attrValue;
+
+ /**
+ * @see cn.orionsec.ops.constant.Const#IS_SYSTEM
+ * @see cn.orionsec.ops.constant.Const#NOT_SYSTEM
+ */
+ @ApiModelProperty(value = "是否为系统变量 1是 2否")
+ @TableField("system_env")
+ private Integer systemEnv;
+
+ @ApiModelProperty(value = "描述")
+ @TableField("description")
+ private String description;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationInfoDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationInfoDO.java
new file mode 100644
index 0000000..050fe1a
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationInfoDO.java
@@ -0,0 +1,56 @@
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "应用表")
+@TableName("application_info")
+public class ApplicationInfoDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "名称")
+ @TableField("app_name")
+ private String appName;
+
+ @ApiModelProperty(value = "应用唯一标识")
+ @TableField("app_tag")
+ private String appTag;
+
+ @ApiModelProperty(value = "排序")
+ @TableField("app_sort")
+ private Integer appSort;
+
+ @ApiModelProperty(value = "应用版本仓库id")
+ @TableField(value = "repo_id", updateStrategy = FieldStrategy.IGNORED)
+ private Long repoId;
+
+ @ApiModelProperty(value = "描述")
+ @TableField("description")
+ private String description;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationMachineDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationMachineDO.java
new file mode 100644
index 0000000..ac12b5e
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationMachineDO.java
@@ -0,0 +1,60 @@
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "应用依赖机器表")
+@TableName("application_machine")
+public class ApplicationMachineDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "应用id")
+ @TableField("app_id")
+ private Long appId;
+
+ @ApiModelProperty(value = "环境id")
+ @TableField("profile_id")
+ private Long profileId;
+
+ @ApiModelProperty(value = "机器id")
+ @TableField("machine_id")
+ private Long machineId;
+
+ @ApiModelProperty(value = "当前版本发布id")
+ @TableField("release_id")
+ private Long releaseId;
+
+ @ApiModelProperty(value = "当前版本构建id")
+ @TableField("build_id")
+ private Long buildId;
+
+ @ApiModelProperty(value = "当前版本构建序列")
+ @TableField("build_seq")
+ private Integer buildSeq;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationPipelineDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationPipelineDO.java
new file mode 100644
index 0000000..0a006d7
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationPipelineDO.java
@@ -0,0 +1,48 @@
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "应用流水线")
+@TableName("application_pipeline")
+public class ApplicationPipelineDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "环境id")
+ @TableField("profile_id")
+ private Long profileId;
+
+ @ApiModelProperty(value = "流水线名称")
+ @TableField("pipeline_name")
+ private String pipelineName;
+
+ @ApiModelProperty(value = "描述")
+ @TableField("description")
+ private String description;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationPipelineDetailDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationPipelineDetailDO.java
new file mode 100644
index 0000000..71638f6
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationPipelineDetailDO.java
@@ -0,0 +1,56 @@
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "应用流水线详情")
+@TableName("application_pipeline_detail")
+@SuppressWarnings("ALL")
+public class ApplicationPipelineDetailDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "流水线id")
+ @TableField("pipeline_id")
+ private Long pipelineId;
+
+ @ApiModelProperty(value = "应用id")
+ @TableField("app_id")
+ private Long appId;
+
+ @ApiModelProperty(value = "环境id")
+ @TableField("profile_id")
+ private Long profileId;
+
+ /**
+ * @see cn.orionsec.ops.constant.app.StageType
+ */
+ @ApiModelProperty(value = "阶段类型 10构建 20发布")
+ @TableField("stage_type")
+ private Integer stageType;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationPipelineTaskDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationPipelineTaskDO.java
new file mode 100644
index 0000000..5af4242
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationPipelineTaskDO.java
@@ -0,0 +1,120 @@
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "应用流水线任务")
+@TableName("application_pipeline_task")
+@SuppressWarnings("ALL")
+public class ApplicationPipelineTaskDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "流水线id")
+ @TableField("pipeline_id")
+ private Long pipelineId;
+
+ @ApiModelProperty(value = "流水线名称")
+ @TableField("pipeline_name")
+ private String pipelineName;
+
+ @ApiModelProperty(value = "环境id")
+ @TableField("profile_id")
+ private Long profileId;
+
+ @ApiModelProperty(value = "环境名称")
+ @TableField("profile_name")
+ private String profileName;
+
+ @ApiModelProperty(value = "环境唯一标识")
+ @TableField("profile_tag")
+ private String profileTag;
+
+ @ApiModelProperty(value = "执行标题")
+ @TableField("exec_title")
+ private String execTitle;
+
+ @ApiModelProperty(value = "执行描述")
+ @TableField("exec_description")
+ private String execDescription;
+
+ /**
+ * @see cn.orionsec.ops.constant.app.PipelineStatus
+ */
+ @ApiModelProperty(value = "执行状态 10待审核 20审核驳回 30待执行 35待调度 40执行中 50执行完成 60执行停止 70执行失败")
+ @TableField("exec_status")
+ private Integer execStatus;
+
+ @ApiModelProperty(value = "是否是定时执行 10普通执行 20定时执行")
+ @TableField("timed_exec")
+ private Integer timedExec;
+
+ @ApiModelProperty(value = "定时执行时间")
+ @TableField("timed_exec_time")
+ private Date timedExecTime;
+
+ @ApiModelProperty(value = "创建人id")
+ @TableField("create_user_id")
+ private Long createUserId;
+
+ @ApiModelProperty(value = "创建人名称")
+ @TableField("create_user_name")
+ private String createUserName;
+
+ @ApiModelProperty(value = "审核人id")
+ @TableField("audit_user_id")
+ private Long auditUserId;
+
+ @ApiModelProperty(value = "审核人名称")
+ @TableField("audit_user_name")
+ private String auditUserName;
+
+ @ApiModelProperty(value = "审核时间")
+ @TableField("audit_time")
+ private Date auditTime;
+
+ @ApiModelProperty(value = "审核备注")
+ @TableField("audit_reason")
+ private String auditReason;
+
+ @ApiModelProperty(value = "执行人id")
+ @TableField("exec_user_id")
+ private Long execUserId;
+
+ @ApiModelProperty(value = "执行人名称")
+ @TableField("exec_user_name")
+ private String execUserName;
+
+ @ApiModelProperty(value = "执行开始时间")
+ @TableField("exec_start_time")
+ private Date execStartTime;
+
+ @ApiModelProperty(value = "执行结束时间")
+ @TableField("exec_end_time")
+ private Date execEndTime;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationPipelineTaskDetailDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationPipelineTaskDetailDO.java
new file mode 100644
index 0000000..0786c88
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationPipelineTaskDetailDO.java
@@ -0,0 +1,95 @@
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "应用流水线任务详情")
+@TableName("application_pipeline_task_detail")
+@SuppressWarnings("ALL")
+public class ApplicationPipelineTaskDetailDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "流水线id")
+ @TableField("pipeline_id")
+ private Long pipelineId;
+
+ @ApiModelProperty(value = "流水线详情id")
+ @TableField("pipeline_detail_id")
+ private Long pipelineDetailId;
+
+ @ApiModelProperty(value = "流水线操作任务id")
+ @TableField("task_id")
+ private Long taskId;
+
+ @ApiModelProperty(value = "引用id")
+ @TableField("rel_id")
+ private Long relId;
+
+ @ApiModelProperty(value = "应用id")
+ @TableField("app_id")
+ private Long appId;
+
+ @ApiModelProperty(value = "应用名称")
+ @TableField("app_name")
+ private String appName;
+
+ @ApiModelProperty(value = "应用唯一标识")
+ @TableField("app_tag")
+ private String appTag;
+
+ /**
+ * @see cn.orionsec.ops.constant.app.StageType
+ */
+ @ApiModelProperty(value = "阶段类型 10构建 20发布")
+ @TableField("stage_type")
+ private Integer stageType;
+
+ /**
+ * @see cn.orionsec.ops.entity.dto.ApplicationPipelineStageConfigDTO
+ */
+ @ApiModelProperty(value = "阶段操作配置")
+ @TableField("stage_config")
+ private String stageConfig;
+
+ /**
+ * @see cn.orionsec.ops.constant.app.PipelineDetailStatus
+ */
+ @ApiModelProperty(value = "状态 10未开始 20进行中 30已完成 40执行失败 50已跳过 60已终止")
+ @TableField("exec_status")
+ private Integer execStatus;
+
+ @ApiModelProperty(value = "执行开始时间")
+ @TableField("exec_start_time")
+ private Date execStartTime;
+
+ @ApiModelProperty(value = "执行结束时间")
+ @TableField("exec_end_time")
+ private Date execEndTime;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationPipelineTaskLogDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationPipelineTaskLogDO.java
new file mode 100644
index 0000000..0d6a64e
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationPipelineTaskLogDO.java
@@ -0,0 +1,64 @@
+
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "应用流水线任务日志")
+@TableName("application_pipeline_task_log")
+@SuppressWarnings("ALL")
+public class ApplicationPipelineTaskLogDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "流水线任务id")
+ @TableField("task_id")
+ private Long taskId;
+
+ @ApiModelProperty(value = "流水线任务详情id")
+ @TableField("task_detail_id")
+ private Long taskDetailId;
+
+ /**
+ * @see cn.orionsec.ops.constant.app.PipelineLogStatus
+ */
+ @ApiModelProperty(value = "日志状态 10创建 20执行 30成功 40失败 50停止 60跳过")
+ @TableField("log_status")
+ private Integer logStatus;
+
+ /**
+ * @see cn.orionsec.ops.constant.app.StageType
+ */
+ @ApiModelProperty(value = "阶段类型 10构建 20发布")
+ @TableField("stage_type")
+ private Integer stageType;
+
+ @ApiModelProperty(value = "日志详情")
+ @TableField("log_info")
+ private String logInfo;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationProfileDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationProfileDO.java
new file mode 100644
index 0000000..5a9cb7b
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationProfileDO.java
@@ -0,0 +1,59 @@
+
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "应用环境表")
+@TableName("application_profile")
+@SuppressWarnings("ALL")
+public class ApplicationProfileDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "环境名称")
+ @TableField("profile_name")
+ private String profileName;
+
+ @ApiModelProperty(value = "环境唯一标识")
+ @TableField("profile_tag")
+ private String profileTag;
+
+ @ApiModelProperty(value = "环境描述")
+ @TableField("description")
+ private String description;
+
+ /**
+ * @see cn.orionsec.ops.constant.Const#ENABLE
+ * @see cn.orionsec.ops.constant.Const#DISABLE
+ */
+ @ApiModelProperty(value = "发布是否需要审核 1需要 2无需")
+ @TableField("release_audit")
+ private Integer releaseAudit;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationReleaseDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationReleaseDO.java
new file mode 100644
index 0000000..a71ef13
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationReleaseDO.java
@@ -0,0 +1,181 @@
+
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "发布任务")
+@TableName("application_release")
+@SuppressWarnings("ALL")
+public class ApplicationReleaseDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "发布标题")
+ @TableField("release_title")
+ private String releaseTitle;
+
+ @ApiModelProperty(value = "发布描述")
+ @TableField("release_description")
+ private String releaseDescription;
+
+ @ApiModelProperty(value = "构建id")
+ @TableField("build_id")
+ private Long buildId;
+
+ @ApiModelProperty(value = "构建seq")
+ @TableField("build_seq")
+ private Integer buildSeq;
+
+ @ApiModelProperty(value = "应用id")
+ @TableField("app_id")
+ private Long appId;
+
+ @ApiModelProperty(value = "应用名称")
+ @TableField("app_name")
+ private String appName;
+
+ @ApiModelProperty(value = "应用唯一标识")
+ @TableField("app_tag")
+ private String appTag;
+
+ @ApiModelProperty(value = "环境id")
+ @TableField("profile_id")
+ private Long profileId;
+
+ @ApiModelProperty(value = "环境名称")
+ @TableField("profile_name")
+ private String profileName;
+
+ @ApiModelProperty(value = "环境唯一标识")
+ @TableField("profile_tag")
+ private String profileTag;
+
+ /**
+ * @see cn.orionsec.ops.constant.app.ReleaseType
+ */
+ @ApiModelProperty(value = "发布类型 10正常发布 20回滚发布")
+ @TableField("release_type")
+ private Integer releaseType;
+
+ /**
+ * @see cn.orionsec.ops.constant.app.ReleaseStatus
+ */
+ @ApiModelProperty(value = "发布状态 10待审核 20审核驳回 30待发布 35待调度 40发布中 50发布完成 60发布停止 70发布失败")
+ @TableField("release_status")
+ private Integer releaseStatus;
+
+ /**
+ * @see cn.orionsec.ops.constant.common.SerialType
+ */
+ @ApiModelProperty(value = "发布序列 10串行 20并行")
+ @TableField("release_serialize")
+ private Integer releaseSerialize;
+
+ /**
+ * @see cn.orionsec.ops.constant.common.ExceptionHandlerType
+ */
+ @ApiModelProperty(value = "异常处理 10跳过所有 20跳过错误")
+ @TableField("exception_handler")
+ private Integer exceptionHandler;
+
+ @ApiModelProperty(value = "构建产物文件")
+ @TableField("bundle_path")
+ private String bundlePath;
+
+ @ApiModelProperty(value = "产物传输路径")
+ @TableField("transfer_path")
+ private String transferPath;
+
+ /**
+ * @see cn.orionsec.ops.constant.app.TransferMode
+ */
+ @ApiModelProperty(value = "产物传输方式")
+ @TableField("transfer_mode")
+ private String transferMode;
+
+ @ApiModelProperty(value = "回滚发布id")
+ @TableField("rollback_release_id")
+ private Long rollbackReleaseId;
+
+ /**
+ * @see cn.orionsec.ops.constant.app.TimedType
+ */
+ @ApiModelProperty(value = "是否是定时发布 10普通发布 20定时发布")
+ @TableField("timed_release")
+ private Integer timedRelease;
+
+ @ApiModelProperty(value = "定时发布时间")
+ @TableField("timed_release_time")
+ private Date timedReleaseTime;
+
+ @ApiModelProperty(value = "创建人id")
+ @TableField("create_user_id")
+ private Long createUserId;
+
+ @ApiModelProperty(value = "创建人名称")
+ @TableField("create_user_name")
+ private String createUserName;
+
+ @ApiModelProperty(value = "审核人id")
+ @TableField("audit_user_id")
+ private Long auditUserId;
+
+ @ApiModelProperty(value = "审核人名称")
+ @TableField("audit_user_name")
+ private String auditUserName;
+
+ @ApiModelProperty(value = "审核时间")
+ @TableField("audit_time")
+ private Date auditTime;
+
+ @ApiModelProperty(value = "审核备注")
+ @TableField("audit_reason")
+ private String auditReason;
+
+ @ApiModelProperty(value = "发布开始时间")
+ @TableField("release_start_time")
+ private Date releaseStartTime;
+
+ @ApiModelProperty(value = "发布结束时间")
+ @TableField("release_end_time")
+ private Date releaseEndTime;
+
+ @ApiModelProperty(value = "发布人id")
+ @TableField("release_user_id")
+ private Long releaseUserId;
+
+ @ApiModelProperty(value = "发布人名称")
+ @TableField("release_user_name")
+ private String releaseUserName;
+
+ @ApiModelProperty(value = "发布操作json")
+ @TableField("action_config")
+ private String actionConfig;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationReleaseMachineDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationReleaseMachineDO.java
new file mode 100644
index 0000000..f524851
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationReleaseMachineDO.java
@@ -0,0 +1,78 @@
+
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "发布任务机器表")
+@TableName("application_release_machine")
+@SuppressWarnings("ALL")
+public class ApplicationReleaseMachineDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "发布任务id")
+ @TableField("release_id")
+ private Long releaseId;
+
+ @ApiModelProperty(value = "机器id")
+ @TableField("machine_id")
+ private Long machineId;
+
+ @ApiModelProperty(value = "机器名称")
+ @TableField("machine_name")
+ private String machineName;
+
+ @ApiModelProperty(value = "机器唯一标识")
+ @TableField("machine_tag")
+ private String machineTag;
+
+ @ApiModelProperty(value = "机器主机")
+ @TableField("machine_host")
+ private String machineHost;
+
+ /**
+ * @see cn.orionsec.ops.constant.app.ActionStatus
+ */
+ @ApiModelProperty(value = "状态 10未开始 20进行中 30已完成 40执行失败 50已跳过 60已取消")
+ @TableField("run_status")
+ private Integer runStatus;
+
+ @ApiModelProperty(value = "日志路径")
+ @TableField("log_path")
+ private String logPath;
+
+ @ApiModelProperty(value = "开始时间")
+ @TableField("start_time")
+ private Date startTime;
+
+ @ApiModelProperty(value = "结束时间")
+ @TableField("end_time")
+ private Date endTime;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationRepositoryDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationRepositoryDO.java
new file mode 100644
index 0000000..c447cca
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/ApplicationRepositoryDO.java
@@ -0,0 +1,91 @@
+
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "应用版本仓库")
+@TableName("application_repository")
+@SuppressWarnings("ALL")
+public class ApplicationRepositoryDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "名称")
+ @TableField("repo_name")
+ private String repoName;
+
+ @ApiModelProperty(value = "描述")
+ @TableField("repo_description")
+ private String repoDescription;
+
+ /**
+ * @see cn.orionsec.ops.constant.app.RepositoryType
+ */
+ @ApiModelProperty(value = "类型 1git")
+ @TableField("repo_type")
+ private Integer repoType;
+
+ @ApiModelProperty(value = "url")
+ @TableField("repo_url")
+ private String repoUrl;
+
+ @ApiModelProperty(value = "用户名")
+ @TableField("repo_username")
+ private String repoUsername;
+
+ @ApiModelProperty(value = "密码")
+ @TableField("repo_password")
+ private String repoPassword;
+
+ @ApiModelProperty(value = "token")
+ @TableField("repo_private_token")
+ private String repoPrivateToken;
+
+ /**
+ * @see cn.orionsec.ops.constant.app.RepositoryStatus
+ */
+ @ApiModelProperty(value = "状态 10未初始化 20初始化中 30正常 40失败")
+ @TableField("repo_status")
+ private Integer repoStatus;
+
+ /**
+ * @see cn.orionsec.ops.constant.app.RepositoryAuthType
+ */
+ @ApiModelProperty(value = "认证类型 10密码 20令牌")
+ @TableField("repo_auth_type")
+ private Integer repoAuthType;
+
+ /**
+ * @see cn.orionsec.ops.constant.app.RepositoryTokenType
+ */
+ @ApiModelProperty(value = "令牌类型 10github 20gitee 30gitlab")
+ @TableField("repo_token_type")
+ private Integer repoTokenType;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "更新时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/CommandExecDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/CommandExecDO.java
new file mode 100644
index 0000000..faf7d7d
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/CommandExecDO.java
@@ -0,0 +1,101 @@
+
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "命令执行表")
+@TableName("command_exec")
+@SuppressWarnings("ALL")
+public class CommandExecDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "用户id")
+ @TableField("user_id")
+ private Long userId;
+
+ @ApiModelProperty(value = "用户名")
+ @TableField("user_name")
+ private String userName;
+
+ /**
+ * @see cn.orionsec.ops.constant.command.ExecType
+ */
+ @ApiModelProperty(value = "执行类型 10批量执行")
+ @TableField("exec_type")
+ private Integer execType;
+
+ @ApiModelProperty(value = "机器id")
+ @TableField("machine_id")
+ private Long machineId;
+
+ @ApiModelProperty(value = "机器名称")
+ @TableField("machine_name")
+ private String machineName;
+
+ @ApiModelProperty(value = "机器主机")
+ @TableField("machine_host")
+ private String machineHost;
+
+ @ApiModelProperty(value = "机器唯一标识")
+ @TableField("machine_tag")
+ private String machineTag;
+
+ /**
+ * @see cn.orionsec.ops.constant.command.ExecStatus
+ */
+ @ApiModelProperty(value = "执行状态 10未开始 20执行中 30执行成功 40执行失败 50执行终止")
+ @TableField("exec_status")
+ private Integer execStatus;
+
+ @ApiModelProperty(value = "执行返回码")
+ @TableField("exit_code")
+ private Integer exitCode;
+
+ @ApiModelProperty(value = "命令")
+ @TableField("exec_command")
+ private String execCommand;
+
+ @ApiModelProperty(value = "描述")
+ @TableField("description")
+ private String description;
+
+ @ApiModelProperty(value = "日志目录")
+ @TableField("log_path")
+ private String logPath;
+
+ @ApiModelProperty(value = "执行开始时间")
+ @TableField("start_date")
+ private Date startDate;
+
+ @ApiModelProperty(value = "执行结束时间")
+ @TableField("end_date")
+ private Date endDate;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/CommandTemplateDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/CommandTemplateDO.java
new file mode 100644
index 0000000..854c2bc
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/CommandTemplateDO.java
@@ -0,0 +1,66 @@
+
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "命令模板表")
+@TableName("command_template")
+public class CommandTemplateDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "模板名称")
+ @TableField("template_name")
+ private String templateName;
+
+ @ApiModelProperty(value = "命令")
+ @TableField("template_value")
+ private String templateValue;
+
+ @ApiModelProperty(value = "命令描述")
+ @TableField("description")
+ private String description;
+
+ @ApiModelProperty(value = "创建用户id")
+ @TableField("create_user_id")
+ private Long createUserId;
+
+ @ApiModelProperty(value = "创建用户名")
+ @TableField("create_user_name")
+ private String createUserName;
+
+ @ApiModelProperty(value = "修改用户id")
+ @TableField("update_user_id")
+ private Long updateUserId;
+
+ @ApiModelProperty(value = "修改用户名")
+ @TableField("update_user_name")
+ private String updateUserName;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/FileTailListDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/FileTailListDO.java
new file mode 100644
index 0000000..51e22b1
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/FileTailListDO.java
@@ -0,0 +1,70 @@
+
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "文件tail表")
+@TableName("file_tail_list")
+@SuppressWarnings("ALL")
+public class FileTailListDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "机器id")
+ @TableField("machine_id")
+ private Long machineId;
+
+ @ApiModelProperty(value = "别名")
+ @TableField("alias_name")
+ private String aliasName;
+
+ @ApiModelProperty(value = "文件路径")
+ @TableField("file_path")
+ private String filePath;
+
+ @ApiModelProperty(value = "文件编码")
+ @TableField("file_charset")
+ private String fileCharset;
+
+ @ApiModelProperty(value = "尾部文件偏移行数")
+ @TableField("file_offset")
+ private Integer fileOffset;
+
+ @ApiModelProperty(value = "tail 命令")
+ @TableField("tail_command")
+ private String tailCommand;
+
+ /**
+ * @see cn.orionsec.ops.constant.tail.FileTailMode
+ */
+ @ApiModelProperty(value = "宿主机文件追踪类型 tracker/tail")
+ @TableField("tail_mode")
+ private String tailMode;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/FileTransferLogDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/FileTransferLogDO.java
new file mode 100644
index 0000000..a5412cf
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/FileTransferLogDO.java
@@ -0,0 +1,89 @@
+
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "sftp传输日志表")
+@TableName("file_transfer_log")
+@SuppressWarnings("ALL")
+public class FileTransferLogDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "用户id")
+ @TableField("user_id")
+ private Long userId;
+
+ @ApiModelProperty(value = "用户名")
+ @TableField("user_name")
+ private String userName;
+
+ @ApiModelProperty(value = "文件token")
+ @TableField("file_token")
+ private String fileToken;
+
+ /**
+ * @see cn.orionsec.ops.constant.sftp.SftpTransferType
+ */
+ @ApiModelProperty(value = "传输类型 10上传 20下载 30传输")
+ @TableField("transfer_type")
+ private Integer transferType;
+
+ @ApiModelProperty(value = "机器id")
+ @TableField("machine_id")
+ private Long machineId;
+
+ @ApiModelProperty(value = "远程文件")
+ @TableField("remote_file")
+ private String remoteFile;
+
+ @ApiModelProperty(value = "本机文件")
+ @TableField("local_file")
+ private String localFile;
+
+ @ApiModelProperty(value = "当前大小")
+ @TableField("current_size")
+ private Long currentSize;
+
+ @ApiModelProperty(value = "文件大小")
+ @TableField("file_size")
+ private Long fileSize;
+
+ @ApiModelProperty(value = "当前进度")
+ @TableField("now_progress")
+ private Double nowProgress;
+
+ /**
+ * @see cn.orionsec.ops.constant.sftp.SftpTransferStatus
+ */
+ @ApiModelProperty(value = "传输状态 10未开始 20进行中 30已暂停 40已完成 50已取消 60传输异常")
+ @TableField("transfer_status")
+ private Integer transferStatus;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/HistoryValueSnapshotDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/HistoryValueSnapshotDO.java
new file mode 100644
index 0000000..3c847ff
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/HistoryValueSnapshotDO.java
@@ -0,0 +1,72 @@
+
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "历史值快照表")
+@TableName("history_value_snapshot")
+@SuppressWarnings("ALL")
+public class HistoryValueSnapshotDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "值id")
+ @TableField("value_id")
+ private Long valueId;
+
+ /**
+ * @see cn.orionsec.ops.constant.history.HistoryOperator
+ */
+ @ApiModelProperty(value = "操作类型 1新增 2修改 3删除")
+ @TableField("operator_type")
+ private Integer operatorType;
+
+ /**
+ * @see cn.orionsec.ops.constant.history.HistoryValueType
+ */
+ @ApiModelProperty(value = "值类型 10机器环境变量 20应用环境变量")
+ @TableField("value_type")
+ private Integer valueType;
+
+ @ApiModelProperty(value = "原始值")
+ @TableField("before_value")
+ private String beforeValue;
+
+ @ApiModelProperty(value = "新值")
+ @TableField("after_value")
+ private String afterValue;
+
+ @ApiModelProperty(value = "修改人id")
+ @TableField("update_user_id")
+ private Long updateUserId;
+
+ @ApiModelProperty(value = "修改人用户名")
+ @TableField("update_user_name")
+ private String updateUserName;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineAlarmConfigDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineAlarmConfigDO.java
new file mode 100644
index 0000000..9359d76
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineAlarmConfigDO.java
@@ -0,0 +1,61 @@
+
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@TableName("machine_alarm_config")
+@ApiModel(value = "MachineAlarmConfigDO对象", description = "机器报警配置")
+@SuppressWarnings("ALL")
+public class MachineAlarmConfigDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "机器id")
+ @TableField("machine_id")
+ private Long machineId;
+
+ /**
+ * @see cn.orionsec.ops.constant.machine.MachineAlarmType
+ */
+ @ApiModelProperty(value = "报警类型 10: cpu使用率 20: 内存使用率")
+ @TableField("alarm_type")
+ private Integer alarmType;
+
+ @ApiModelProperty(value = "报警阈值")
+ @TableField("alarm_threshold")
+ private Double alarmThreshold;
+
+ @ApiModelProperty(value = "触发报警阈值 次")
+ @TableField("trigger_threshold")
+ private Integer triggerThreshold;
+
+ @ApiModelProperty(value = "报警通知沉默时间 分")
+ @TableField("notify_silence")
+ private Integer notifySilence;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineAlarmGroupDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineAlarmGroupDO.java
new file mode 100644
index 0000000..a6d5b95
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineAlarmGroupDO.java
@@ -0,0 +1,46 @@
+
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@TableName("machine_alarm_group")
+@ApiModel(value = "MachineAlarmGroupDO对象", description = "机器报警通知组")
+public class MachineAlarmGroupDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "机器id")
+ @TableField("machine_id")
+ private Long machineId;
+
+ @ApiModelProperty(value = " 报警组id")
+ @TableField("group_id")
+ private Long groupId;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineAlarmHistoryDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineAlarmHistoryDO.java
new file mode 100644
index 0000000..9622738
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineAlarmHistoryDO.java
@@ -0,0 +1,55 @@
+
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@TableName("machine_alarm_history")
+@ApiModel(value = "MachineAlarmHistoryDO对象", description = "机器报警历史")
+@SuppressWarnings("ALL")
+public class MachineAlarmHistoryDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "机器id")
+ @TableField("machine_id")
+ private Long machineId;
+
+ /**
+ * @see cn.orionsec.ops.constant.machine.MachineAlarmType
+ */
+ @ApiModelProperty(value = "报警类型 10: cpu使用率 20: 内存使用率")
+ @TableField("alarm_type")
+ private Integer alarmType;
+
+ @ApiModelProperty(value = "报警值")
+ @TableField("alarm_value")
+ private Double alarmValue;
+
+ @ApiModelProperty(value = "报警时间")
+ @TableField("alarm_time")
+ private Date alarmTime;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @TableField("create_time")
+ private Date createTime;
+
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineEnvDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineEnvDO.java
new file mode 100644
index 0000000..f2b239a
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineEnvDO.java
@@ -0,0 +1,53 @@
+
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "机器环境变量")
+@TableName("machine_env")
+public class MachineEnvDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "机器id")
+ @TableField("machine_id")
+ private Long machineId;
+
+ @ApiModelProperty(value = "key")
+ @TableField("attr_key")
+ private String attrKey;
+
+ @ApiModelProperty(value = "value")
+ @TableField("attr_value")
+ private String attrValue;
+
+ @ApiModelProperty(value = "描述")
+ @TableField("description")
+ private String description;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineGroupDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineGroupDO.java
new file mode 100644
index 0000000..59f66ab
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineGroupDO.java
@@ -0,0 +1,50 @@
+
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@TableName("machine_group")
+@ApiModel(value = "MachineGroupDO对象", description = "机器分组")
+public class MachineGroupDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "父id")
+ @TableField("parent_id")
+ private Long parentId;
+
+ @ApiModelProperty(value = "组名称")
+ @TableField("group_name")
+ private String groupName;
+
+ @ApiModelProperty(value = "排序")
+ @TableField("sort")
+ private Integer sort;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineGroupRelDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineGroupRelDO.java
new file mode 100644
index 0000000..da1146c
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineGroupRelDO.java
@@ -0,0 +1,45 @@
+
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@TableName("machine_group_rel")
+@ApiModel(value = "MachineGroupRelDO对象", description = "机器分组关联表")
+public class MachineGroupRelDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "组id")
+ @TableField("group_id")
+ private Long groupId;
+
+ @ApiModelProperty(value = "机器id")
+ @TableField("machine_id")
+ private Long machineId;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineInfoDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineInfoDO.java
new file mode 100644
index 0000000..b43bc71
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineInfoDO.java
@@ -0,0 +1,90 @@
+
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "机器信息表")
+@TableName("machine_info")
+@SuppressWarnings("ALL")
+public class MachineInfoDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "代理id")
+ @TableField(value = "proxy_id", updateStrategy = FieldStrategy.IGNORED)
+ private Long proxyId;
+
+ @ApiModelProperty(value = "密钥id")
+ @TableField(value = "key_id", updateStrategy = FieldStrategy.IGNORED)
+ private Long keyId;
+
+ @ApiModelProperty(value = "主机ip")
+ @TableField("machine_host")
+ private String machineHost;
+
+ @ApiModelProperty(value = "ssh端口")
+ @TableField("ssh_port")
+ private Integer sshPort;
+
+ @ApiModelProperty(value = "机器名称")
+ @TableField("machine_name")
+ private String machineName;
+
+ @ApiModelProperty(value = "机器唯一标识")
+ @TableField("machine_tag")
+ private String machineTag;
+
+ @ApiModelProperty(value = "机器描述")
+ @TableField("description")
+ private String description;
+
+ @ApiModelProperty(value = "机器账号")
+ @TableField("username")
+ private String username;
+
+ @ApiModelProperty(value = "机器密码")
+ @TableField("password")
+ private String password;
+
+ /**
+ * @see cn.orionsec.ops.constant.machine.MachineAuthType
+ */
+ @ApiModelProperty(value = "机器认证方式 1: 密码认证 2: 独立密钥")
+ @TableField("auth_type")
+ private Integer authType;
+
+ /**
+ * @see cn.orionsec.ops.constant.Const#ENABLE
+ * @see cn.orionsec.ops.constant.Const#DISABLE
+ */
+ @ApiModelProperty(value = "机器状态 1有效 2无效")
+ @TableField("machine_status")
+ private Integer machineStatus;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineMonitorDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineMonitorDO.java
new file mode 100644
index 0000000..1ba955f
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineMonitorDO.java
@@ -0,0 +1,61 @@
+
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "机器监控配置表")
+@TableName("machine_monitor")
+@SuppressWarnings("ALL")
+public class MachineMonitorDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "机器id")
+ @TableField("machine_id")
+ private Long machineId;
+
+ /**
+ * @see cn.orionsec.ops.constant.monitor.MonitorStatus
+ */
+ @ApiModelProperty(value = "插件状态 1未安装 2安装中 3未运行 4运行中")
+ @TableField("monitor_status")
+ private Integer monitorStatus;
+
+ @ApiModelProperty(value = "请求 api url")
+ @TableField("monitor_url")
+ private String monitorUrl;
+
+ @ApiModelProperty(value = "请求 api accessToken")
+ @TableField("access_token")
+ private String accessToken;
+
+ @ApiModelProperty(value = "插件版本")
+ @TableField("agent_version")
+ private String agentVersion;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineProxyDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineProxyDO.java
new file mode 100644
index 0000000..226f220
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineProxyDO.java
@@ -0,0 +1,65 @@
+
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "机器代理")
+@TableName("machine_proxy")
+@SuppressWarnings("ALL")
+public class MachineProxyDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "代理主机")
+ @TableField("proxy_host")
+ private String proxyHost;
+
+ @ApiModelProperty(value = "代理端口")
+ @TableField("proxy_port")
+ private Integer proxyPort;
+
+ @ApiModelProperty(value = "代理用户名")
+ @TableField("proxy_username")
+ private String proxyUsername;
+
+ @ApiModelProperty(value = "代理密码")
+ @TableField("proxy_password")
+ private String proxyPassword;
+
+ /**
+ * @see cn.orionsec.ops.constant.machine.ProxyType
+ */
+ @ApiModelProperty(value = "代理类型 1http代理 2socket4代理 3socket5代理")
+ @TableField("proxy_type")
+ private Integer proxyType;
+
+ @ApiModelProperty(value = "描述")
+ @TableField("description")
+ private String description;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineSecretKeyDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineSecretKeyDO.java
new file mode 100644
index 0000000..bbde0cf
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineSecretKeyDO.java
@@ -0,0 +1,53 @@
+
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "机器ssh登录密钥")
+@TableName("machine_secret_key")
+public class MachineSecretKeyDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "密钥名称")
+ @TableField("key_name")
+ private String keyName;
+
+ @ApiModelProperty(value = "密钥文件本地路径")
+ @TableField("secret_key_path")
+ private String secretKeyPath;
+
+ @ApiModelProperty(value = "密钥密码")
+ @TableField("password")
+ private String password;
+
+ @ApiModelProperty(value = "描述")
+ @TableField("description")
+ private String description;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineTerminalDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineTerminalDO.java
new file mode 100644
index 0000000..49ed010
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineTerminalDO.java
@@ -0,0 +1,85 @@
+
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "机器终端配置表")
+@TableName("machine_terminal")
+@SuppressWarnings("ALL")
+public class MachineTerminalDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "机器id")
+ @TableField("machine_id")
+ private Long machineId;
+
+ /**
+ * @see cn.orionsec.kit.net.host.ssh.TerminalType#XTERM
+ */
+ @ApiModelProperty(value = "终端类型")
+ @TableField("terminal_type")
+ private String terminalType;
+
+ /**
+ * @see cn.orionsec.ops.constant.terminal.TerminalConst#BACKGROUND_COLOR
+ */
+ @ApiModelProperty(value = "背景色")
+ @TableField("background_color")
+ private String backgroundColor;
+
+ /**
+ * @see cn.orionsec.ops.constant.terminal.TerminalConst#FONT_COLOR
+ */
+ @ApiModelProperty(value = "字体颜色")
+ @TableField("font_color")
+ private String fontColor;
+
+ /**
+ * @see cn.orionsec.ops.constant.terminal.TerminalConst#FONT_SIZE
+ */
+ @ApiModelProperty(value = "字体大小")
+ @TableField("font_size")
+ private Integer fontSize;
+
+ /**
+ * @see cn.orionsec.ops.constant.terminal.TerminalConst#FONT_FAMILY
+ */
+ @ApiModelProperty(value = "字体名称")
+ @TableField("font_family")
+ private String fontFamily;
+
+ /**
+ * @see cn.orionsec.ops.constant.Const#ENABLE
+ * @see cn.orionsec.ops.constant.Const#DISABLE
+ */
+ @ApiModelProperty(value = "是否开启url link 1开启 2关闭")
+ @TableField("enable_web_link")
+ private Integer enableWebLink;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineTerminalLogDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineTerminalLogDO.java
new file mode 100644
index 0000000..295b4ea
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/MachineTerminalLogDO.java
@@ -0,0 +1,84 @@
+
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "机器终端操作日志")
+@TableName("machine_terminal_log")
+@SuppressWarnings("ALL")
+public class MachineTerminalLogDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "用户id")
+ @TableField("user_id")
+ private Long userId;
+
+ @ApiModelProperty(value = "用户名")
+ @TableField("username")
+ private String username;
+
+ @ApiModelProperty(value = "机器id")
+ @TableField("machine_id")
+ private Long machineId;
+
+ @ApiModelProperty(value = "机器名称")
+ @TableField("machine_name")
+ private String machineName;
+
+ @ApiModelProperty(value = "机器唯一标识")
+ @TableField("machine_tag")
+ private String machineTag;
+
+ @ApiModelProperty(value = "机器host")
+ @TableField("machine_host")
+ private String machineHost;
+
+ @ApiModelProperty(value = "token")
+ @TableField("access_token")
+ private String accessToken;
+
+ @ApiModelProperty(value = "建立连接时间")
+ @TableField("connected_time")
+ private Date connectedTime;
+
+ @ApiModelProperty(value = "断开连接时间")
+ @TableField("disconnected_time")
+ private Date disconnectedTime;
+
+ /**
+ * @see cn.orionsec.ops.constant.ws.WsCloseCode
+ */
+ @ApiModelProperty(value = "close code")
+ @TableField("close_code")
+ private Integer closeCode;
+
+ @ApiModelProperty(value = "录屏文件路径")
+ @TableField("screen_path")
+ private String screenPath;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/SchedulerTaskDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/SchedulerTaskDO.java
new file mode 100644
index 0000000..513d14b
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/SchedulerTaskDO.java
@@ -0,0 +1,87 @@
+
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "调度任务")
+@TableName("scheduler_task")
+@SuppressWarnings("ALL")
+public class SchedulerTaskDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "任务名称")
+ @TableField("task_name")
+ private String taskName;
+
+ @ApiModelProperty(value = "任务描述")
+ @TableField("description")
+ private String description;
+
+ @ApiModelProperty(value = "执行命令")
+ @TableField("task_command")
+ private String taskCommand;
+
+ @ApiModelProperty(value = "cron表达式")
+ @TableField("expression")
+ private String expression;
+
+ /**
+ * @see cn.orionsec.ops.constant.Const#ENABLE
+ * @see cn.orionsec.ops.constant.Const#DISABLE
+ */
+ @ApiModelProperty(value = "启用状态 1启用 2停用")
+ @TableField("enable_status")
+ private Integer enableStatus;
+
+ /**
+ * @see cn.orionsec.ops.constant.scheduler.SchedulerTaskStatus
+ */
+ @ApiModelProperty(value = "最近状态 10待调度 20调度中 30调度成功 40调度失败 50已停止")
+ @TableField("lately_status")
+ private Integer latelyStatus;
+
+ /**
+ * @see cn.orionsec.ops.constant.common.SerialType
+ */
+ @ApiModelProperty(value = "调度序列 10串行 20并行")
+ @TableField("serialize_type")
+ private Integer serializeType;
+
+ /**
+ * @see cn.orionsec.ops.constant.common.ExceptionHandlerType
+ */
+ @ApiModelProperty(value = "异常处理 10跳过所有 20跳过错误")
+ @TableField("exception_handler")
+ private Integer exceptionHandler;
+
+ @ApiModelProperty(value = "上次调度时间")
+ @TableField(value = "lately_schedule_time")
+ private Date latelyScheduleTime;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/SchedulerTaskMachineDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/SchedulerTaskMachineDO.java
new file mode 100644
index 0000000..36fb290
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/SchedulerTaskMachineDO.java
@@ -0,0 +1,45 @@
+
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "调度任务机器")
+@TableName("scheduler_task_machine")
+public class SchedulerTaskMachineDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "任务id")
+ @TableField("task_id")
+ private Long taskId;
+
+ @ApiModelProperty(value = "调度机器id")
+ @TableField("machine_id")
+ private Long machineId;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/SchedulerTaskMachineRecordDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/SchedulerTaskMachineRecordDO.java
new file mode 100644
index 0000000..32a3aa5
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/SchedulerTaskMachineRecordDO.java
@@ -0,0 +1,94 @@
+
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "调度任务执行明细机器详情")
+@TableName("scheduler_task_machine_record")
+@SuppressWarnings("ALL")
+public class SchedulerTaskMachineRecordDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "任务id")
+ @TableField("task_id")
+ private Long taskId;
+
+ @ApiModelProperty(value = "明细id")
+ @TableField("record_id")
+ private Long recordId;
+
+ @ApiModelProperty(value = "任务机器id")
+ @TableField("task_machine_id")
+ private Long taskMachineId;
+
+ @ApiModelProperty(value = "执行机器id")
+ @TableField("machine_id")
+ private Long machineId;
+
+ @ApiModelProperty(value = "机器名称")
+ @TableField("machine_name")
+ private String machineName;
+
+ @ApiModelProperty(value = "机器主机")
+ @TableField("machine_host")
+ private String machineHost;
+
+ @ApiModelProperty(value = "机器唯一标识")
+ @TableField("machine_tag")
+ private String machineTag;
+
+ @ApiModelProperty(value = "执行命令")
+ @TableField("exec_command")
+ private String execCommand;
+
+ /**
+ * @see cn.orionsec.ops.constant.scheduler.SchedulerTaskMachineStatus
+ */
+ @ApiModelProperty(value = "执行状态 10待调度 20调度中 30调度成功 40调度失败 50已跳过 60已停止")
+ @TableField("exec_status")
+ private Integer execStatus;
+
+ @ApiModelProperty(value = "退出码")
+ @TableField("exit_code")
+ private Integer exitCode;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "日志路径")
+ @TableField("log_path")
+ private String logPath;
+
+ @ApiModelProperty(value = "开始时间")
+ @TableField("start_time")
+ private Date startTime;
+
+ @ApiModelProperty(value = "结束时间")
+ @TableField("end_time")
+ private Date endTime;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/SchedulerTaskRecordDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/SchedulerTaskRecordDO.java
new file mode 100644
index 0000000..16c6243
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/SchedulerTaskRecordDO.java
@@ -0,0 +1,62 @@
+
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "调度任务执行日志")
+@TableName("scheduler_task_record")
+@SuppressWarnings("ALL")
+public class SchedulerTaskRecordDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "任务id")
+ @TableField("task_id")
+ private Long taskId;
+
+ @ApiModelProperty(value = "任务名称")
+ @TableField("task_name")
+ private String taskName;
+
+ /**
+ * @see cn.orionsec.ops.constant.scheduler.SchedulerTaskStatus
+ */
+ @ApiModelProperty(value = "任务状态 10待调度 20调度中 30调度成功 40调度失败 50已停止")
+ @TableField("task_status")
+ private Integer taskStatus;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "开始时间")
+ @TableField("start_time")
+ private Date startTime;
+
+ @ApiModelProperty(value = "结束时间")
+ @TableField("end_time")
+ private Date endTime;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/SystemEnvDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/SystemEnvDO.java
new file mode 100644
index 0000000..6f2f2a9
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/SystemEnvDO.java
@@ -0,0 +1,59 @@
+
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "系统环境变量")
+@TableName("system_env")
+@SuppressWarnings("ALL")
+public class SystemEnvDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "key")
+ @TableField("attr_key")
+ private String attrKey;
+
+ @ApiModelProperty(value = "value")
+ @TableField("attr_value")
+ private String attrValue;
+
+ /**
+ * @see cn.orionsec.ops.constant.Const#IS_SYSTEM
+ * @see cn.orionsec.ops.constant.Const#NOT_SYSTEM
+ */
+ @ApiModelProperty(value = "是否为系统变量 1是 2否")
+ @TableField("system_env")
+ private Integer systemEnv;
+
+ @ApiModelProperty(value = "描述")
+ @TableField("description")
+ private String description;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/UserEventLogDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/UserEventLogDO.java
new file mode 100644
index 0000000..22c7ff6
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/UserEventLogDO.java
@@ -0,0 +1,73 @@
+
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "用户事件日志")
+@TableName("user_event_log")
+@SuppressWarnings("ALL")
+public class UserEventLogDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "用户id")
+ @TableField("user_id")
+ private Long userId;
+
+ @ApiModelProperty(value = "用户名")
+ @TableField("username")
+ private String username;
+
+ /**
+ * @see cn.orionsec.ops.constant.event.EventClassify
+ */
+ @ApiModelProperty(value = "事件分类")
+ @TableField("event_classify")
+ private Integer eventClassify;
+
+ /**
+ * @see cn.orionsec.ops.constant.event.EventType
+ */
+ @ApiModelProperty(value = "事件类型")
+ @TableField("event_type")
+ private Integer eventType;
+
+ @ApiModelProperty(value = "日志信息")
+ @TableField("log_info")
+ private String logInfo;
+
+ @ApiModelProperty(value = "日志参数")
+ @TableField("params_json")
+ private String paramsJson;
+
+ /**
+ * @see cn.orionsec.ops.constant.Const#ENABLE
+ * @see cn.orionsec.ops.constant.Const#DISABLE
+ */
+ @ApiModelProperty(value = "是否执行成功 1成功 2失败")
+ @TableField("exec_result")
+ private Integer execResult;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/UserInfoDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/UserInfoDO.java
new file mode 100644
index 0000000..bddd6e6
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/UserInfoDO.java
@@ -0,0 +1,98 @@
+
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "用户表")
+@TableName("user_info")
+@SuppressWarnings("ALL")
+public class UserInfoDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "用户名")
+ @TableField("username")
+ private String username;
+
+ @ApiModelProperty(value = "昵称")
+ @TableField("nickname")
+ private String nickname;
+
+ @ApiModelProperty(value = "密码")
+ @TableField("password")
+ private String password;
+
+ @ApiModelProperty(value = "盐值")
+ @TableField("salt")
+ private String salt;
+
+ /**
+ * @see cn.orionsec.ops.constant.user.RoleType
+ */
+ @ApiModelProperty(value = "角色类型 10管理员 20开发 30运维")
+ @TableField("role_type")
+ private Integer roleType;
+
+ /**
+ * @see cn.orionsec.ops.constant.Const#ENABLE
+ * @see cn.orionsec.ops.constant.Const#DISABLE
+ */
+ @ApiModelProperty(value = "用户状态 1启用 2禁用")
+ @TableField("user_status")
+ private Integer userStatus;
+
+ /**
+ * @see cn.orionsec.ops.constant.Const#ENABLE
+ * @see cn.orionsec.ops.constant.Const#DISABLE
+ */
+ @ApiModelProperty(value = "锁定状态 1正常 2锁定")
+ @TableField("lock_status")
+ private Integer lockStatus;
+
+ @ApiModelProperty(value = "登录失败次数")
+ @TableField("failed_login_count")
+ private Integer failedLoginCount;
+
+ @ApiModelProperty(value = "头像地址")
+ @TableField("avatar_pic")
+ private String avatarPic;
+
+ @ApiModelProperty(value = "联系手机")
+ @TableField("contact_phone")
+ private String contactPhone;
+
+ @ApiModelProperty(value = "联系邮箱")
+ @TableField("contact_email")
+ private String contactEmail;
+
+ @ApiModelProperty(value = "最后登录时间")
+ @TableField("last_login_time")
+ private Date lastLoginTime;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/WebSideMessageDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/WebSideMessageDO.java
new file mode 100644
index 0000000..efd0391
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/WebSideMessageDO.java
@@ -0,0 +1,76 @@
+
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "系统站内信")
+@TableName("web_side_message")
+@SuppressWarnings("ALL")
+public class WebSideMessageDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ /**
+ * @see cn.orionsec.ops.constant.message.MessageClassify
+ */
+ @ApiModelProperty(value = "消息分类")
+ @TableField("message_classify")
+ private Integer messageClassify;
+
+ /**
+ * @see cn.orionsec.ops.constant.message.MessageType
+ */
+ @ApiModelProperty(value = "消息类型")
+ @TableField("message_type")
+ private Integer messageType;
+
+ /**
+ * @see cn.orionsec.ops.constant.message.ReadStatus
+ */
+ @ApiModelProperty(value = "是否已读 1未读 2已读")
+ @TableField("read_status")
+ private Integer readStatus;
+
+ @ApiModelProperty(value = "收信人id")
+ @TableField("to_user_id")
+ private Long toUserId;
+
+ @ApiModelProperty(value = "收信人名称")
+ @TableField("to_user_name")
+ private String toUserName;
+
+ @ApiModelProperty(value = "消息")
+ @TableField("send_message")
+ private String sendMessage;
+
+ @ApiModelProperty(value = "消息关联id")
+ @TableField("rel_id")
+ private Long relId;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "修改时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/WebhookConfigDO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/WebhookConfigDO.java
new file mode 100644
index 0000000..28f34e9
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/domain/WebhookConfigDO.java
@@ -0,0 +1,57 @@
+
+package cn.orionsec.ops.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@TableName("webhook_config")
+@ApiModel(value = "WebhookConfigDO对象", description = "webhook 配置")
+@SuppressWarnings("ALL")
+public class WebhookConfigDO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty(value = "名称")
+ @TableField("webhook_name")
+ private String webhookName;
+
+ @ApiModelProperty(value = "url")
+ @TableField("webhook_url")
+ private String webhookUrl;
+
+ /**
+ * @see cn.orionsec.ops.constant.webhook.WebhookType
+ */
+ @ApiModelProperty(value = "类型 10: 钉钉机器人")
+ @TableField("webhook_type")
+ private Integer webhookType;
+
+ @ApiModelProperty(value = "配置项 json")
+ @TableField("webhook_config")
+ private String webhookConfig;
+
+ @ApiModelProperty(value = "是否删除 1未删除 2已删除")
+ @TableLogic
+ private Integer deleted;
+
+ @ApiModelProperty(value = "创建时间")
+ @TableField("create_time")
+ private Date createTime;
+
+ @ApiModelProperty(value = "更新时间")
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/dto/ApplicationActionConfigDTO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/dto/ApplicationActionConfigDTO.java
new file mode 100644
index 0000000..1c9142a
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/dto/ApplicationActionConfigDTO.java
@@ -0,0 +1,22 @@
+
+package cn.orionsec.ops.entity.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+
+@Data
+@ApiModel(value = "检查应用是否已配置")
+public class ApplicationActionConfigDTO {
+
+ @ApiModelProperty(value = "appId")
+ private Long appId;
+
+ @ApiModelProperty(value = "构建阶段数量")
+ private Integer buildStageCount;
+
+ @ApiModelProperty(value = "发布阶段数量")
+ private Integer releaseStageCount;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/dto/ApplicationBuildStatisticsDTO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/dto/ApplicationBuildStatisticsDTO.java
new file mode 100644
index 0000000..35e68a8
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/dto/ApplicationBuildStatisticsDTO.java
@@ -0,0 +1,29 @@
+
+package cn.orionsec.ops.entity.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+@ApiModel(value = "应用构建统计")
+public class ApplicationBuildStatisticsDTO {
+
+ @ApiModelProperty(value = "构建次数")
+ private Integer buildCount;
+
+ @ApiModelProperty(value = "成功次数")
+ private Integer successCount;
+
+ @ApiModelProperty(value = "失败次数")
+ private Integer failureCount;
+
+ @ApiModelProperty(value = "日期")
+ private Date date;
+
+ @ApiModelProperty(value = "平均构建时长ms (成功)")
+ private Long avgUsed;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/dto/ApplicationPipelineTaskStatisticsDTO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/dto/ApplicationPipelineTaskStatisticsDTO.java
new file mode 100644
index 0000000..769de49
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/dto/ApplicationPipelineTaskStatisticsDTO.java
@@ -0,0 +1,30 @@
+
+package cn.orionsec.ops.entity.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+
+@Data
+@ApiModel(value = "应用流水线统计")
+public class ApplicationPipelineTaskStatisticsDTO {
+
+ @ApiModelProperty(value = "执行次数")
+ private Integer execCount;
+
+ @ApiModelProperty(value = "成功次数")
+ private Integer successCount;
+
+ @ApiModelProperty(value = "失败次数")
+ private Integer failureCount;
+
+ @ApiModelProperty(value = "日期")
+ private Date date;
+
+ @ApiModelProperty(value = "平均执行时长ms (成功)")
+ private Long avgUsed;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/dto/ApplicationReleaseStatisticsDTO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/dto/ApplicationReleaseStatisticsDTO.java
new file mode 100644
index 0000000..c6d3a84
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/dto/ApplicationReleaseStatisticsDTO.java
@@ -0,0 +1,29 @@
+
+package cn.orionsec.ops.entity.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+@ApiModel(value = "应用发布统计")
+public class ApplicationReleaseStatisticsDTO {
+
+ @ApiModelProperty(value = "发布次数")
+ private Integer releaseCount;
+
+ @ApiModelProperty(value = "成功次数")
+ private Integer successCount;
+
+ @ApiModelProperty(value = "失败次数")
+ private Integer failureCount;
+
+ @ApiModelProperty(value = "日期")
+ private Date date;
+
+ @ApiModelProperty(value = "平均发布时长ms (成功)")
+ private Long avgUsed;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/dto/MachineMonitorDTO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/dto/MachineMonitorDTO.java
new file mode 100644
index 0000000..126139b
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/dto/MachineMonitorDTO.java
@@ -0,0 +1,45 @@
+
+package cn.orionsec.ops.entity.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "机器监控配置")
+@SuppressWarnings("ALL")
+public class MachineMonitorDTO implements Serializable {
+
+ @ApiModelProperty(value = "id")
+ private Long id;
+
+ @ApiModelProperty(value = "机器id")
+ private Long machineId;
+
+ @ApiModelProperty(value = "机器名称")
+ private String machineName;
+
+ @ApiModelProperty(value = "机器主机")
+ private String machineHost;
+
+ /**
+ * @see cn.orionsec.ops.constant.monitor.MonitorStatus
+ */
+ @ApiModelProperty(value = "监控状态 1未安装 2安装中 3未运行 4运行中")
+ private Integer monitorStatus;
+
+ @ApiModelProperty(value = "请求 api url")
+ private String monitorUrl;
+
+ @ApiModelProperty(value = "请求 api accessToken")
+ private String accessToken;
+
+ @ApiModelProperty(value = "插件版本")
+ private String agentVersion;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/dto/SchedulerTaskRecordStatisticsDTO.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/dto/SchedulerTaskRecordStatisticsDTO.java
new file mode 100644
index 0000000..60acba3
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/dto/SchedulerTaskRecordStatisticsDTO.java
@@ -0,0 +1,35 @@
+
+package cn.orionsec.ops.entity.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+@ApiModel(value = "调度任务机器执行统计")
+public class SchedulerTaskRecordStatisticsDTO {
+
+ @ApiModelProperty(value = "调度次数")
+ private Integer scheduledCount;
+
+ @ApiModelProperty(value = "成功次数")
+ private Integer successCount;
+
+ @ApiModelProperty(value = "失败次数")
+ private Integer failureCount;
+
+ @ApiModelProperty(value = "日期")
+ private Date date;
+
+ @ApiModelProperty(value = "机器平均执行时长ms (成功)")
+ private Long avgUsed;
+
+ @ApiModelProperty(value = "机器id")
+ private Long machineId;
+
+ @ApiModelProperty(value = "机器名称")
+ private String machineName;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/query/MachineMonitorQuery.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/query/MachineMonitorQuery.java
new file mode 100644
index 0000000..0f76045
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/entity/query/MachineMonitorQuery.java
@@ -0,0 +1,25 @@
+
+package cn.orionsec.ops.entity.query;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+@ApiModel(value = "机器监控查询参数")
+@SuppressWarnings("ALL")
+public class MachineMonitorQuery {
+
+ @ApiModelProperty(value = "机器id")
+ private Long machineId;
+
+ @ApiModelProperty(value = "机器名称")
+ private String machineName;
+
+ /**
+ * @see cn.orionsec.ops.constant.monitor.MonitorStatus
+ */
+ @ApiModelProperty(value = "监控状态 1未安装 2安装中 3未运行 4运行中")
+ private Integer monitorStatus;
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/utils/CodeGenerator.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/utils/CodeGenerator.java
new file mode 100644
index 0000000..180a3fa
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/utils/CodeGenerator.java
@@ -0,0 +1,190 @@
+
+package cn.orionsec.ops.utils;
+
+import cn.orionsec.kit.lang.constant.Const;
+import cn.orionsec.kit.lang.utils.Strings;
+import cn.orionsec.kit.lang.utils.Systems;
+import cn.orionsec.kit.lang.utils.ext.PropertiesExt;
+import com.baomidou.mybatisplus.annotation.DbType;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.generator.AutoGenerator;
+import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
+import com.baomidou.mybatisplus.generator.config.GlobalConfig;
+import com.baomidou.mybatisplus.generator.config.PackageConfig;
+import com.baomidou.mybatisplus.generator.config.StrategyConfig;
+import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
+import com.baomidou.mybatisplus.generator.config.rules.DateType;
+import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
+import com.baomidou.mybatisplus.generator.config.rules.IColumnType;
+import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
+
+import java.io.File;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+public class CodeGenerator {
+
+ private static final Pattern ENV_VAR_PATTERN = Pattern.compile("\\$\\{([^:]+):([^}]+)\\}");
+
+ public static void main(String[] args) {
+ runGenerator();
+ }
+
+ /**
+ * 代码生成器
+ */
+ private static void runGenerator() {
+ // 获取配置文件
+ File file = new File("orion-ops-api/orion-ops-web/src/main/resources/application-dev.properties");
+ PropertiesExt ext = new PropertiesExt(file);
+ String url = resolveConfigValue(ext.getValue("spring.datasource.url"));
+ String username = resolveConfigValue(ext.getValue("spring.datasource.username"));
+ String password = resolveConfigValue(ext.getValue("spring.datasource.password"));
+ // 全局配置
+ GlobalConfig gbConfig = new GlobalConfig()
+ // 是否支持AR模式
+ .setActiveRecord(false)
+ // 设置作者
+ .setAuthor(Const.ORION_AUTHOR)
+ // 生成路径
+ .setOutputDir("D:/MP/")
+ // 文件是否覆盖
+ .setFileOverride(true)
+ // 主键策略
+ .setIdType(IdType.AUTO)
+ // Service名称
+ .setServiceName("%sService")
+ // 业务实现类名称
+ .setServiceImplName("%sServiceImpl")
+ // 实体对象名名称
+ .setEntityName("%sDO")
+ // 映射接口名称
+ .setMapperName("%sDAO")
+ // 映射文件名称
+ .setXmlName("%sMapper")
+ // web名称
+ .setControllerName("%sController")
+ // 生成 swagger2 注解
+ .setSwagger2(true)
+ // 开启 Kotlin 模式
+ .setKotlin(false)
+ // 是否生成ResultMap
+ .setBaseResultMap(true)
+ // 是否生成二级缓存
+ .setEnableCache(false)
+ // date类型
+ .setDateType(DateType.ONLY_DATE)
+ // 是否生成SQL片段
+ .setBaseColumnList(true);
+
+ // 数据源配置
+ DataSourceConfig dsConfig = new DataSourceConfig()
+ // 配置数据库类型
+ .setDbType(DbType.MYSQL)
+ // 配置驱动
+ .setDriverName("com.mysql.cj.jdbc.Driver")
+ // 配置路径
+ .setUrl(url)
+ // 配置账号
+ .setUsername(username)
+ // 配置密码
+ .setPassword(password)
+ // 转换器
+ .setTypeConvert(new MySqlTypeConvert() {
+ @Override
+ public IColumnType processTypeConvert(GlobalConfig globalConfig, String fieldType) {
+ if (fieldType.toLowerCase().contains("tinyint")) {
+ return DbColumnType.INTEGER;
+ }
+ return super.processTypeConvert(globalConfig, fieldType);
+ }
+ });
+
+ // 策略配置
+ StrategyConfig stConfig = new StrategyConfig()
+ // 全局大写命名
+ .setCapitalMode(true)
+ // 生成实体类注解
+ .setEntityTableFieldAnnotationEnable(true)
+ // 是否使用lombok写get set 方法
+ .setEntityLombokModel(true)
+ // 前端是否使用 @RestController
+ .setRestControllerStyle(true)
+ // 驼峰转连接字符
+ .setControllerMappingHyphenStyle(false)
+ // Boolean类型字段是否移除is前缀
+ .setEntityBooleanColumnRemoveIsPrefix(false)
+ // 下滑线转驼峰命名策略
+ .setNaming(NamingStrategy.underline_to_camel)
+ // 是否生成字段常量
+ .setEntityColumnConstant(false)
+ // 是否链式结构
+ .setChainModel(false)
+ // 配置表前缀
+ .setTablePrefix("")
+ // 配置字段前缀
+ .setFieldPrefix("")
+ // 生成的表
+ .setInclude("machine_group", "machine_group_rel");
+
+ // 包名策略配置
+ PackageConfig pkConfig = new PackageConfig()
+ // 声明父包
+ .setParent("cn.orionsec.ops")
+ // 映射接口的包
+ .setMapper("dao")
+ // service接口的包
+ .setService("service")
+ // serviceImpl接口的包
+ .setServiceImpl("service.impl")
+ // controller接口的包
+ .setController("controller")
+ // 实体类的包
+ .setEntity("entity.domain")
+ // 映射文件的包
+ .setXml("mapper");
+
+ // 整合配置
+ AutoGenerator ag = new AutoGenerator()
+ // 整合全局配置
+ .setGlobalConfig(gbConfig)
+ // 整合数据源配置
+ .setDataSource(dsConfig)
+ // 整合表名配置
+ .setStrategy(stConfig)
+ // 整合包名策略
+ .setPackageInfo(pkConfig);
+
+ // 执行
+ ag.execute();
+ }
+
+ /**
+ * 解析实际的配置
+ *
+ * @param value value
+ * @return value
+ */
+ private static String resolveConfigValue(String value) {
+ if (Strings.isBlank(value)) {
+ return value;
+ }
+ Matcher matcher = ENV_VAR_PATTERN.matcher(value);
+ StringBuffer resultString = new StringBuffer();
+ while (matcher.find()) {
+ // 环境变量名
+ String envVar = matcher.group(1);
+ // 默认值
+ String defaultValue = matcher.group(2);
+ // 获取环境变量的值
+ String envValue = Systems.getEnv(envVar, defaultValue);
+ // 替换占位符
+ matcher.appendReplacement(resultString, Matcher.quoteReplacement(envValue));
+ }
+ // 处理结尾的剩余部分
+ matcher.appendTail(resultString);
+ return resultString.toString();
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/utils/DataQuery.java b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/utils/DataQuery.java
new file mode 100644
index 0000000..623726d
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/java/cn/orionsec/ops/utils/DataQuery.java
@@ -0,0 +1,99 @@
+
+package cn.orionsec.ops.utils;
+
+import cn.orionsec.kit.lang.define.wrapper.DataGrid;
+import cn.orionsec.kit.lang.define.wrapper.PageRequest;
+import cn.orionsec.kit.lang.define.wrapper.Pager;
+import cn.orionsec.kit.lang.utils.Valid;
+import cn.orionsec.kit.lang.utils.collect.Lists;
+import cn.orionsec.kit.lang.utils.convert.Converts;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class DataQuery {
+
+ private final BaseMapper dao;
+
+ private PageRequest page;
+
+ private LambdaQueryWrapper wrapper;
+
+ private DataQuery(BaseMapper dao) {
+ this.dao = dao;
+ }
+
+ public static DataQuery of(BaseMapper dao) {
+ Valid.notNull(dao, "dao is null");
+ return new DataQuery<>(dao);
+ }
+
+ public DataQuery page(PageRequest page) {
+ this.page = Valid.notNull(page, "page is null");
+ return this;
+ }
+
+ public DataQuery wrapper(LambdaQueryWrapper wrapper) {
+ this.wrapper = Valid.notNull(wrapper, "wrapper is null");
+ return this;
+ }
+
+ public Optional get() {
+ return Optional.ofNullable(dao.selectOne(wrapper));
+ }
+
+ public Optional get(Class c) {
+ return Optional.ofNullable(dao.selectOne(wrapper))
+ .map(s -> Converts.to(s, c));
+ }
+
+ public Stream list() {
+ return dao.selectList(wrapper).stream();
+ }
+
+ public List list(Class c) {
+ return Converts.toList(dao.selectList(wrapper), c);
+ }
+
+ public Integer count() {
+ return dao.selectCount(wrapper);
+ }
+
+ public boolean present() {
+ return dao.selectCount(wrapper) > 0;
+ }
+
+ public DataGrid dataGrid() {
+ return this.dataGrid(Function.identity());
+ }
+
+ public DataGrid dataGrid(Class c) {
+ return this.dataGrid(t -> Converts.to(t, c));
+ }
+
+ public DataGrid dataGrid(Function convert) {
+ Valid.notNull(convert, "convert is null");
+ Valid.notNull(page, "page is null");
+ Valid.notNull(wrapper, "wrapper is null");
+ Integer count = dao.selectCount(wrapper);
+ Pager pager = new Pager<>(page);
+ pager.setTotal(count);
+ boolean next = pager.hasMoreData();
+ if (next) {
+ wrapper.last(pager.getSql());
+ List rows = dao.selectList(wrapper).stream()
+ .map(convert)
+ .collect(Collectors.toList());
+ pager.setRows(rows);
+ } else {
+ pager.setRows(Lists.empty());
+ }
+ return DataGrid.of(pager);
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/AlarmGroupMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/AlarmGroupMapper.xml
new file mode 100644
index 0000000..b4b8e41
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/AlarmGroupMapper.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id
+ , group_name, group_description, deleted, create_time, update_time
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/AlarmGroupNotifyMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/AlarmGroupNotifyMapper.xml
new file mode 100644
index 0000000..a3ee534
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/AlarmGroupNotifyMapper.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id
+ , group_id, notify_id, notify_type, deleted, create_time, update_time
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/AlarmGroupUserMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/AlarmGroupUserMapper.xml
new file mode 100644
index 0000000..085b402
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/AlarmGroupUserMapper.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id
+ , group_id, user_id, username, deleted, create_time, update_time
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationActionLogMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationActionLogMapper.xml
new file mode 100644
index 0000000..584f229
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationActionLogMapper.xml
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, stage_type, rel_id, machine_id, action_id, action_name, action_type, action_command, log_path, run_status,
+ exit_code, start_time, end_time, deleted, create_time, update_time
+
+
+
+
+ SELECT id, rel_id, run_status, start_time, end_time, exit_code
+ FROM application_action_log
+
+
+
+
+ WHERE id = #{id}
+ AND deleted = 1
+
+
+
+
+ WHERE id IN
+
+ #{id}
+
+ AND deleted = 1
+
+
+
+
+ WHERE stage_type = #{stageType}
+ AND rel_id = #{relId}
+ AND deleted = 1
+
+
+
+
+ WHERE stage_type = #{stageType}
+ AND rel_id IN
+
+ #{relId}
+
+ AND deleted = 1
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationActionMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationActionMapper.xml
new file mode 100644
index 0000000..4ba6afa
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationActionMapper.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, app_id, profile_id, action_name, action_type, stage_type, action_command, deleted, create_time, update_time
+
+
+
+ SELECT app_id,
+ COUNT(stage_type = 10 OR NULL) build_stage_count,
+ COUNT(stage_type = 20 OR NULL) release_stage_count
+ FROM application_action
+ WHERE profile_id = #{profileId}
+ AND app_id IN
+
+ #{appId}
+
+ AND deleted = 1
+ GROUP BY app_id
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationBuildMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationBuildMapper.xml
new file mode 100644
index 0000000..d514348
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationBuildMapper.xml
@@ -0,0 +1,160 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, app_id, app_name, app_tag, profile_id, profile_name, profile_tag,
+ build_seq, branch_name, commit_id, repo_id, log_path, bundle_path, build_status, description,
+ create_user_id, create_user_name, build_start_time, build_end_time, deleted, create_time, update_time
+
+
+
+ SELECT build_status
+ FROM application_build
+ WHERE id = #{id}
+ AND deleted = 1
+
+
+
+ SELECT id, build_status, build_start_time, build_end_time
+ FROM application_build
+ WHERE id = #{id}
+ AND deleted = 1
+
+
+
+ SELECT id, build_status, build_start_time, build_end_time
+ FROM application_build
+ WHERE id IN
+
+ #{id}
+
+ AND deleted = 1
+
+
+
+ SELECT branch_name
+ FROM application_build
+ WHERE repo_id = #{repoId}
+
+ AND app_id = #{appId}
+
+
+ AND profile_id = #{profileId}
+
+ AND branch_name IS NOT NULL
+ AND deleted = 1
+ ORDER BY id DESC
+ LIMIT 1
+
+
+
+ SELECT build_seq
+ FROM application_build
+ WHERE id = #{id}
+ AND deleted = 1
+
+
+
+ SELECT id, build_seq, description, create_time
+ FROM application_build
+ WHERE app_id = #{appId}
+ AND profile_id = #{profileId}
+ AND build_status = 30
+ AND deleted = 1
+ ORDER by id DESC
+ LIMIT #{limit}
+
+
+
+ SELECT id, app_id,
+ FROM application_build
+ WHERE app_id IN
+
+ #{appId}
+
+ AND profile_id = #{profileId}
+ AND build_status = 30
+ AND deleted = 1
+ GROUP BY app_id
+ ORDER by id DESC
+
+
+
+ SELECT
+ COUNT(1) build_count,
+ COUNT(build_status = 30 OR NULL) success_count,
+ COUNT(build_status = 40 OR NULL) failure_count,
+ IFNULL(
+ FLOOR(
+ AVG(
+ IF(
+ build_status = 30
+ AND build_end_time IS NOT NULL
+ AND build_start_time IS NOT NULL,
+ UNIX_TIMESTAMP(build_end_time) * 1000 - UNIX_TIMESTAMP(build_start_time) * 1000,
+ NULL
+ )
+ )
+ ), 0
+ ) avg_used
+ FROM application_build
+ WHERE deleted = 1
+ AND app_id = #{appId}
+ AND profile_id = #{profileId}
+
+ AND create_time >= #{rangeStartDate}
+
+
+
+
+ SELECT
+ COUNT(1) build_count,
+ COUNT(build_status = 30 OR NULL) success_count,
+ COUNT(build_status = 40 OR NULL) failure_count,
+ DATE_FORMAT(create_time, '%Y-%m-%d') date
+ FROM application_build
+ WHERE deleted = 1
+ AND app_id = #{appId}
+ AND profile_id = #{profileId}
+ AND create_time >= #{rangeStartDate}
+ GROUP BY date
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationEnvMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationEnvMapper.xml
new file mode 100644
index 0000000..77593ef
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationEnvMapper.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, app_id, profile_id, attr_key, attr_value, system_env, description, deleted, create_time, update_time
+
+
+
+ SELECT
+
+ FROM application_env
+ WHERE app_id = #{appId}
+ AND profile_id = #{profileId}
+ AND attr_key = #{key}
+ LIMIT 1
+
+
+
+ UPDATE application_env
+ SET deleted = #{deleted}
+ WHERE id = #{id}
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationInfoMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationInfoMapper.xml
new file mode 100644
index 0000000..a6239aa
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationInfoMapper.xml
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, app_name, app_tag, app_sort, repo_id, description, deleted, create_time, update_time
+
+
+
+ SELECT count(1)
+ FROM application_info
+ WHERE repo_id = #{repoId}
+ AND deleted = 1
+
+
+
+ UPDATE application_info
+ SET repo_id = null
+ WHERE repo_id = #{repoId}
+ AND deleted = 1
+
+
+
+ SELECT app_name
+ FROM application_info
+ WHERE id = #{id}
+ AND deleted = 1
+
+
+
+ SELECT id, app_name
+ FROM application_info
+ WHERE deleted = 1
+ AND id IN
+
+ #{id}
+
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationMachineMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationMachineMapper.xml
new file mode 100644
index 0000000..0df3a6e
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationMachineMapper.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, app_id, profile_id, machine_id, release_id, build_id, build_seq, deleted, create_time, update_time
+
+
+
+ UPDATE application_machine
+ SET release_id = #{releaseId},
+ build_id = #{buildId},
+ build_seq = #{buildSeq}
+ WHERE app_id = #{appId}
+ AND profile_id = #{profileId}
+ AND machine_id = #{machineId}
+ AND deleted = 1
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationPipelineDetailMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationPipelineDetailMapper.xml
new file mode 100644
index 0000000..c919754
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationPipelineDetailMapper.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, pipeline_id, app_id, profile_id, stage_type, deleted, create_time, update_time
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationPipelineMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationPipelineMapper.xml
new file mode 100644
index 0000000..7c430ab
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationPipelineMapper.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, profile_id, pipeline_name, description, deleted, create_time, update_time
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationPipelineTaskDetailMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationPipelineTaskDetailMapper.xml
new file mode 100644
index 0000000..ac63015
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationPipelineTaskDetailMapper.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, pipeline_id, pipeline_detail_id, task_id, rel_id, app_id, app_name, app_tag, stage_type, stage_config, exec_status, exec_start_time, exec_end_time, deleted, create_time, update_time
+
+
+
+ id, task_id, rel_id, exec_status, exec_start_time, exec_end_time
+
+
+
+ SELECT
+
+ FROM application_pipeline_task_detail
+ WHERE task_id = #{taskId}
+
+
+
+ SELECT
+
+ FROM application_pipeline_task_detail
+ WHERE id IN
+
+ #{id}
+
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationPipelineTaskLogMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationPipelineTaskLogMapper.xml
new file mode 100644
index 0000000..b1ceda2
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationPipelineTaskLogMapper.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, task_id, task_detail_id, log_status, stage_type, log_info, deleted, create_time, update_time
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationPipelineTaskMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationPipelineTaskMapper.xml
new file mode 100644
index 0000000..13978c0
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationPipelineTaskMapper.xml
@@ -0,0 +1,115 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, pipeline_id, pipeline_name, profile_id, profile_name, profile_tag, exec_title, exec_description, exec_status, timed_exec, timed_exec_time, create_user_id, create_user_name, audit_user_id, audit_user_name, audit_time, audit_reason, exec_user_id, exec_user_name, exec_start_time, exec_end_time, deleted, create_time, update_time
+
+
+
+ id, exec_status, exec_start_time, exec_end_time
+
+
+
+
+
+ SELECT
+
+ FROM application_pipeline_task
+ WHERE id = #{id}
+ AND deleted = 1
+
+
+
+ SELECT
+
+ FROM application_pipeline_task
+ WHERE id IN
+
+ #{id}
+
+ AND deleted = 1
+
+
+
+ SELECT
+ COUNT(1) exec_count,
+ COUNT(exec_status = 50 OR NULL) success_count,
+ COUNT(exec_status = 70 OR NULL) failure_count,
+ IFNULL(
+ FLOOR(
+ AVG(
+ IF(
+ exec_status = 50
+ AND exec_end_time IS NOT NULL
+ AND exec_start_time IS NOT NULL,
+ UNIX_TIMESTAMP(exec_end_time) * 1000 - UNIX_TIMESTAMP(exec_start_time) * 1000,
+ NULL
+ )
+ )
+ ), 0
+ ) avg_used
+ FROM application_pipeline_task
+ WHERE deleted = 1
+ AND pipeline_id = #{pipelineId}
+
+ AND exec_start_time >= #{rangeStartDate}
+
+
+
+
+ SELECT
+ COUNT(1) exec_count,
+ COUNT(exec_status = 50 OR NULL) success_count,
+ COUNT(exec_status = 70 OR NULL) failure_count,
+ DATE_FORMAT(exec_start_time, '%Y-%m-%d') date
+ FROM application_pipeline_task
+ WHERE deleted = 1
+ AND pipeline_id = #{pipelineId}
+ AND exec_start_time >= #{rangeStartDate}
+ GROUP BY date
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationProfileMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationProfileMapper.xml
new file mode 100644
index 0000000..df9ff85
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationProfileMapper.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, profile_name, profile_tag, description, release_audit, deleted, create_time, update_time
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationReleaseMachineMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationReleaseMachineMapper.xml
new file mode 100644
index 0000000..087a138
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationReleaseMachineMapper.xml
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, release_id, machine_id, machine_name, machine_tag, machine_host, run_status, log_path, start_time, end_time, deleted, create_time, update_time
+
+
+
+ id, release_id, run_status, start_time, end_time
+
+
+
+ SELECT
+
+ FROM application_release_machine
+ WHERE release_id = #{releaseId}
+
+
+
+ SELECT
+
+ FROM application_release_machine
+ WHERE release_id IN
+
+ #{releaseId}
+
+ AND deleted = 1
+
+
+
+ SELECT
+
+ FROM application_release_machine
+ WHERE id = #{id}
+ AND deleted = 1
+
+
+
+ SELECT
+
+ FROM application_release_machine
+ WHERE id IN
+
+ #{id}
+
+ AND deleted = 1
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationReleaseMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationReleaseMapper.xml
new file mode 100644
index 0000000..63bc1d9
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationReleaseMapper.xml
@@ -0,0 +1,130 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, release_title, release_description, build_id, build_seq, app_id, app_name, app_tag, profile_id, profile_name, profile_tag,
+ release_type, release_status, release_serialize, exception_handler, bundle_path, transfer_path, transfer_mode, rollback_release_id, timed_release, timed_release_time, create_user_id, create_user_name, audit_user_id, audit_user_name, audit_time, audit_reason,
+ release_start_time, release_end_time, release_user_id, release_user_name, action_config, deleted, create_time, update_time
+
+
+
+ id, release_status, release_start_time, release_end_time
+
+
+
+
+
+ SELECT
+
+ FROM application_release
+ WHERE id = #{id}
+ AND deleted = 1
+
+
+
+ SELECT
+
+ FROM application_release
+ WHERE id IN
+
+ #{id}
+
+ AND deleted = 1
+
+
+
+ SELECT
+ COUNT(1) release_count,
+ COUNT(release_status = 50 OR NULL) success_count,
+ COUNT(release_status = 70 OR NULL) failure_count,
+ IFNULL(
+ FLOOR(
+ AVG(
+ IF(
+ release_status = 50
+ AND release_end_time IS NOT NULL
+ AND release_start_time IS NOT NULL,
+ UNIX_TIMESTAMP(release_end_time) * 1000 - UNIX_TIMESTAMP(release_start_time) * 1000,
+ NULL
+ )
+ )
+ ), 0
+ ) avg_used
+ FROM application_release
+ WHERE deleted = 1
+ AND app_id = #{appId}
+ AND profile_id = #{profileId}
+
+ AND release_start_time >= #{rangeStartDate}
+
+
+
+
+ SELECT
+ COUNT(1) release_count,
+ COUNT(release_status = 50 OR NULL) success_count,
+ COUNT(release_status = 70 OR NULL) failure_count,
+ DATE_FORMAT(release_start_time, '%Y-%m-%d') date
+ FROM application_release
+ WHERE deleted = 1
+ AND app_id = #{appId}
+ AND profile_id = #{profileId}
+ AND release_start_time >= #{rangeStartDate}
+ GROUP BY date
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationRepositoryMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationRepositoryMapper.xml
new file mode 100644
index 0000000..6b8961a
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ApplicationRepositoryMapper.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, repo_name, repo_description, repo_type, repo_url, repo_username, repo_password, repo_private_token,
+ repo_status, repo_auth_type, repo_token_type, deleted, create_time, update_time
+
+
+
+ SELECT id, repo_name
+ FROM application_repository
+ WHERE id IN
+
+ #{id}
+
+ AND deleted = 1
+
+
+
+ SELECT id, repo_name
+ FROM application_repository
+ WHERE repo_name IN
+
+ #{name}
+
+ AND deleted = 1
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/CommandExecMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/CommandExecMapper.xml
new file mode 100644
index 0000000..973596f
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/CommandExecMapper.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, user_id, user_name, exec_type, machine_id, machine_name, machine_host, machine_tag, exec_status, exit_code, exec_command,
+ description, log_path, start_date, end_date, deleted, create_time, update_time
+
+
+
+ SELECT id, exec_status, exit_code, start_date, end_date
+ FROM command_exec
+ WHERE id = #{id}
+ AND deleted = 1
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/CommandTemplateMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/CommandTemplateMapper.xml
new file mode 100644
index 0000000..f4e0fd1
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/CommandTemplateMapper.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, template_name, template_value, description, create_user_id, create_user_name,
+ update_user_id, update_user_name, deleted, create_time, update_time
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/FileTailListMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/FileTailListMapper.xml
new file mode 100644
index 0000000..4fb951d
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/FileTailListMapper.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, machine_id, alias_name, file_path, file_charset, file_offset, tail_command, tail_mode, deleted, create_time, update_time
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/FileTransferLogMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/FileTransferLogMapper.xml
new file mode 100644
index 0000000..83d9540
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/FileTransferLogMapper.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, user_id, user_name, file_token, transfer_type, machine_id, remote_file, local_file, current_size, file_size, now_progress, transfer_status, deleted, create_time, update_time
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/HistoryValueSnapshotMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/HistoryValueSnapshotMapper.xml
new file mode 100644
index 0000000..654059d
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/HistoryValueSnapshotMapper.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, value_id, operator_type, value_type, before_value, after_value, update_user_id, update_user_name, create_time, update_time
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineAlarmConfigMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineAlarmConfigMapper.xml
new file mode 100644
index 0000000..beb2442
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineAlarmConfigMapper.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id
+ , machine_id, alarm_type, alarm_threshold, trigger_threshold, notify_silence, deleted, create_time, update_time
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineAlarmGroupMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineAlarmGroupMapper.xml
new file mode 100644
index 0000000..e747f37
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineAlarmGroupMapper.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id
+ , machine_id, group_id, deleted, create_time, update_time
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineAlarmHistoryMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineAlarmHistoryMapper.xml
new file mode 100644
index 0000000..c12cff9
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineAlarmHistoryMapper.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id
+ , machine_id, alarm_type, alarm_value, alarm_time, deleted, create_time, update_time
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineEnvMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineEnvMapper.xml
new file mode 100644
index 0000000..82df557
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineEnvMapper.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, machine_id, attr_key, attr_value, description, deleted, create_time, update_time
+
+
+
+ SELECT
+
+ FROM machine_env
+ WHERE machine_id = #{machineId}
+ AND attr_key = #{key}
+
+
+
+ UPDATE machine_env
+ SET deleted = #{deleted}
+ WHERE id = #{id}
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineGroupMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineGroupMapper.xml
new file mode 100644
index 0000000..137bb74
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineGroupMapper.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id
+ , parent_id, group_name, sort, deleted, create_time, update_time
+
+
+
+ UPDATE machine_group
+ SET sort = sort + 1
+ WHERE parent_id = #{parentId}
+
+ AND sort > #{greaterSort}
+
+
+
+
+ SELECT max(sort)
+ FROM machine_group
+ WHERE parent_id = #{parentId}
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineGroupRelMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineGroupRelMapper.xml
new file mode 100644
index 0000000..f4489de
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineGroupRelMapper.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id
+ , group_id, machine_id, deleted, create_time, update_time
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineInfoMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineInfoMapper.xml
new file mode 100644
index 0000000..3e65004
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineInfoMapper.xml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, proxy_id, machine_host, ssh_port, machine_name, machine_tag, description, username, password, auth_type, machine_status, deleted, create_time, update_time
+
+
+
+ UPDATE machine_info
+ SET id = #{newId}
+ WHERE id = #{oldId}
+
+
+
+ UPDATE machine_info
+ SET proxy_id = null
+ WHERE proxy_id = #{proxyId}
+
+
+
+ SELECT id
+ FROM machine_info
+ WHERE machine_host LIKE CONCAT('%', #{host}, '%')
+ AND deleted = 1
+
+
+
+ SELECT machine_name
+ FROM machine_info
+ WHERE id = #{id}
+
+
+
+ SELECT id, machine_name, machine_tag, machine_host
+ FROM machine_info
+ WHERE id IN
+
+ #{id}
+
+ AND deleted = 1
+
+
+
+ SELECT id, machine_name, machine_tag, machine_host
+ FROM machine_info
+ WHERE machine_tag IN
+
+ #{tag}
+
+ AND deleted = 1
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineMonitorMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineMonitorMapper.xml
new file mode 100644
index 0000000..c039d26
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineMonitorMapper.xml
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, machine_id, monitor_status, monitor_url, access_token, agent_version, deleted, create_time, update_time
+
+
+
+
+ WHERE deleted = 1
+ AND machine_status = 1
+
+ AND machine_name LIKE concat('%', #{query.machineName}, '%')
+
+
+ AND machine_id = #{query.machineId}
+
+
+ AND monitor_status = #{query.monitorStatus}
+
+
+
+
+ SELECT m.id id,
+ IFNULL(m.monitor_status, 1) monitor_status,
+ m.monitor_url monitor_url,
+ m.access_token access_token,
+ m.agent_version agent_version,
+ i.id machine_id,
+ i.machine_name machine_name,
+ i.machine_host machine_host,
+ i.machine_status machine_status,
+ i.deleted deleted
+ FROM machine_monitor m
+ RIGHT JOIN machine_info i ON i.id = m.machine_id
+
+
+
+ SELECT *
+ FROM (
+
+ ) t
+
+
+ ${last}
+
+
+
+
+ SELECT COUNT(1)
+ FROM (
+
+ ) t
+
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineProxyMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineProxyMapper.xml
new file mode 100644
index 0000000..97901dc
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineProxyMapper.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, proxy_host, proxy_port, proxy_username, proxy_password, description, deleted, create_time, update_time
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineSecretKeyMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineSecretKeyMapper.xml
new file mode 100644
index 0000000..dcab3f6
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineSecretKeyMapper.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id
+ , key_name, secret_key_path, password, description, deleted, create_time, update_time
+
+
+
+ SELECT
+
+ FROM machine_secret_key
+ WHERE key_name IN
+
+ #{name}
+
+ AND deleted = 1
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineTerminalLogMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineTerminalLogMapper.xml
new file mode 100644
index 0000000..2a29965
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineTerminalLogMapper.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, user_id, username, machine_id, machine_name, machine_host, machine_tag, access_token, connected_time, disconnected_time, close_code, screen_path, create_time, update_time
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineTerminalMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineTerminalMapper.xml
new file mode 100644
index 0000000..f39425f
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/MachineTerminalMapper.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, machine_id, terminal_type, background_color, font_color, font_size, font_family,
+ enable_web_link, deleted, create_time, update_time
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ScheduleTaskMachineMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ScheduleTaskMachineMapper.xml
new file mode 100644
index 0000000..3933f82
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ScheduleTaskMachineMapper.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, task_id, machine_id, deleted, create_time, update_time
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ScheduleTaskMachineRecordMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ScheduleTaskMachineRecordMapper.xml
new file mode 100644
index 0000000..4c9b1cc
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ScheduleTaskMachineRecordMapper.xml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, task_id, record_id, task_machine_id, machine_id, machine_name, machine_host, machine_tag, exec_command,
+ exec_status, exit_code, deleted, log_path, start_time, end_time, create_time, update_time
+
+
+
+
+ id, record_id, exec_status, exit_code, start_time, end_time
+
+
+
+ SELECT
+
+ FROM scheduler_task_machine_record
+ WHERE record_id = #{recordId}
+
+
+
+ SELECT
+
+ FROM scheduler_task_machine_record
+ WHERE id IN
+
+ #{id}
+
+
+
+
+ SELECT
+
+ FROM scheduler_task_machine_record
+ WHERE record_id IN
+
+ #{recordId}
+
+
+
+
+ UPDATE scheduler_task_machine_record
+ SET deleted = 2
+ WHERE record_id IN
+
+ #{recordId}
+
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ScheduleTaskMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ScheduleTaskMapper.xml
new file mode 100644
index 0000000..02089f6
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ScheduleTaskMapper.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, task_name, description, task_command, expression, enable_status, lately_status, serialize_type, exception_handler, lately_schedule_time, deleted, create_time, update_time
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ScheduleTaskRecordMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ScheduleTaskRecordMapper.xml
new file mode 100644
index 0000000..73af256
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/ScheduleTaskRecordMapper.xml
@@ -0,0 +1,111 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, task_id, task_name, task_status, deleted, start_time, end_time, create_time, update_time
+
+
+
+
+ id, task_status, start_time, end_time
+
+
+
+ SELECT
+
+ FROM scheduler_task_record
+ WHERE id IN
+
+ #{id}
+
+
+
+
+ SELECT
+ COUNT(1) scheduled_count,
+ COUNT(task_status = 30 OR NULL) success_count,
+ COUNT(task_status = 40 OR NULL) failure_count,
+ IFNULL(
+ FLOOR(
+ AVG(
+ IF(
+ task_status = 30
+ AND end_time IS NOT NULL
+ AND start_time IS NOT NULL,
+ UNIX_TIMESTAMP(end_time) * 1000 - UNIX_TIMESTAMP(start_time) * 1000,
+ NULL
+ )
+ )
+ ), 0
+ ) avg_used
+ FROM scheduler_task_record
+ WHERE deleted = 1
+ AND task_id = #{taskId}
+ AND create_time >= #{rangeStartDate}
+
+
+
+ SELECT
+ machine_name,
+ machine_id,
+ COUNT(1) scheduled_count,
+ COUNT(exec_status = 30 OR NULL) success_count,
+ COUNT(exec_status = 40 OR NULL) failure_count,
+ FLOOR(
+ AVG(
+ IF(
+ exec_status = 30
+ AND end_time IS NOT NULL
+ AND start_time IS NOT NULL,
+ UNIX_TIMESTAMP( end_time ) * 1000 - UNIX_TIMESTAMP( start_time ) * 1000,
+ NULL
+ )
+ )
+ ) avg_used
+ FROM scheduler_task_machine_record
+ WHERE deleted = 1
+ AND task_id = #{taskId}
+ GROUP BY machine_id
+ ORDER BY id DESC
+
+
+
+ SELECT
+ COUNT(1) scheduled_count,
+ COUNT(task_status = 30 OR NULL) success_count,
+ COUNT(task_status = 40 OR NULL) failure_count,
+ DATE_FORMAT(create_time, '%Y-%m-%d') date
+ FROM scheduler_task_record
+ WHERE deleted = 1
+ AND task_id = #{taskId}
+ AND create_time >= #{rangeStartDate}
+ GROUP BY date
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/SystemEnvMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/SystemEnvMapper.xml
new file mode 100644
index 0000000..94461f4
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/SystemEnvMapper.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, attr_key, attr_value, system_env, description, deleted, create_time, update_time
+
+
+
+ SELECT
+
+ FROM system_env
+ WHERE attr_key = #{key}
+
+
+
+ UPDATE system_env
+ SET deleted = #{deleted}
+ WHERE id = #{id}
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/UserEventLogMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/UserEventLogMapper.xml
new file mode 100644
index 0000000..25df2f0
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/UserEventLogMapper.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, user_id, username, event_classify, event_type, log_info, params_json, exec_result, deleted, create_time
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/UserInfoMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/UserInfoMapper.xml
new file mode 100644
index 0000000..b9fdcb5
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/UserInfoMapper.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id, username, nickname, password, salt, role_type, user_status, lock_status, failed_login_count, avatar_pic, contact_phone, contact_email, last_login_time, deleted, create_time, update_time
+
+
+
+ UPDATE user_info
+ SET last_login_time = now(),
+ update_time = now()
+ WHERE id = #{userId}
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/WebSideMessageMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/WebSideMessageMapper.xml
new file mode 100644
index 0000000..2588381
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/WebSideMessageMapper.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id
+ , message_classify, message_type, read_status, to_user_id, to_user_name, send_message, deleted, rel_id, create_time, update_time
+
+
+
diff --git a/orion-ops-api/orion-ops-dao/src/main/resources/mapper/WebhookConfigMapper.xml b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/WebhookConfigMapper.xml
new file mode 100644
index 0000000..7e89fda
--- /dev/null
+++ b/orion-ops-api/orion-ops-dao/src/main/resources/mapper/WebhookConfigMapper.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id
+ , webhook_name, webhook_url, webhook_type, webhook_config, deleted, create_time, update_time
+
+
+
diff --git a/orion-ops-api/orion-ops-data/pom.xml b/orion-ops-api/orion-ops-data/pom.xml
new file mode 100644
index 0000000..347a9b1
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/pom.xml
@@ -0,0 +1,30 @@
+
+
+
+ cn.orionsec.ops
+ orion-ops-api
+ 1.3.1
+ ../pom.xml
+
+
+ orion-ops-data
+ orion-ops-data
+ 4.0.0
+
+
+
+
+ cn.orionsec.kit
+ orion-all
+
+
+
+
+ cn.orionsec.ops
+ orion-ops-service
+ ${project.version}
+
+
+
+
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/DataModuleConversionProvider.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/DataModuleConversionProvider.java
new file mode 100644
index 0000000..3215ee9
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/DataModuleConversionProvider.java
@@ -0,0 +1,5 @@
+
+package cn.orionsec.ops;
+
+public class DataModuleConversionProvider {
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/constant/DataClearRange.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/constant/DataClearRange.java
new file mode 100644
index 0000000..ed4c636
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/constant/DataClearRange.java
@@ -0,0 +1,43 @@
+
+package cn.orionsec.ops.constant;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+
+@Getter
+@AllArgsConstructor
+public enum DataClearRange {
+
+ /**
+ * 保留天数
+ */
+ DAY(10),
+
+ /**
+ * 保留条数
+ */
+ TOTAL(20),
+
+ /**
+ * 关联数据
+ */
+ REL_ID(30),
+
+ ;
+
+ private final Integer range;
+
+ public static DataClearRange of(Integer range) {
+ if (range == null) {
+ return null;
+ }
+ for (DataClearRange value : values()) {
+ if (value.range.equals(range)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/constant/DataClearType.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/constant/DataClearType.java
new file mode 100644
index 0000000..388b067
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/constant/DataClearType.java
@@ -0,0 +1,70 @@
+
+package cn.orionsec.ops.constant;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+
+@Getter
+@AllArgsConstructor
+public enum DataClearType {
+
+ /**
+ * 批量执行命令记录
+ */
+ BATCH_EXEC(10, "批量执行命令记录"),
+
+ /**
+ * 终端日志记录
+ */
+ TERMINAL_LOG(20, "终端日志记录"),
+
+ /**
+ * 定时调度任务执行记录
+ */
+ SCHEDULER_RECORD(30, "定时调度任务执行记录"),
+
+ /**
+ * 应用构建记录
+ */
+ APP_BUILD(40, "应用构建记录"),
+
+ /**
+ * 应用发布记录
+ */
+ APP_RELEASE(50, "应用发布记录"),
+
+ /**
+ * 应用流水线执行记录
+ */
+ APP_PIPELINE_EXEC(60, "应用流水线执行记录"),
+
+ /**
+ * 用户操作日志
+ */
+ USER_EVENT_LOG(70, "用户操作日志记录"),
+
+ /**
+ * 机器报警历史记录
+ */
+ MACHINE_ALARM_HISTORY(80, "机器报警历史记录"),
+
+ ;
+
+ private final Integer type;
+
+ private final String label;
+
+ public static DataClearType of(Integer type) {
+ if (type == null) {
+ return null;
+ }
+ for (DataClearType value : values()) {
+ if (value.type.equals(type)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/constant/ExportConst.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/constant/ExportConst.java
new file mode 100644
index 0000000..102a430
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/constant/ExportConst.java
@@ -0,0 +1,45 @@
+
+package cn.orionsec.ops.constant;
+
+import cn.orionsec.kit.lang.utils.Strings;
+import cn.orionsec.kit.lang.utils.time.Dates;
+
+
+public class ExportConst {
+
+ private ExportConst() {
+ }
+
+ public static final String MACHINE_EXPORT_NAME = "机器信息导出-{}.xlsx";
+
+ public static final String MACHINE_PROXY_EXPORT_NAME = "机器代理导出-{}.xlsx";
+
+ public static final String MACHINE_ALARM_HISTORY_EXPORT_NAME = "机器报警记录导出-{}.xlsx";
+
+ public static final String TERMINAL_LOG_EXPORT_NAME = "终端日志导出-{}.xlsx";
+
+ public static final String TAIL_FILE_EXPORT_NAME = "日志文件导出-{}.xlsx";
+
+ public static final String APP_PROFILE_EXPORT_NAME = "应用环境导出-{}.xlsx";
+
+ public static final String APPLICATION_EXPORT_NAME = "应用信息导出-{}.xlsx";
+
+ public static final String APP_REPOSITORY_EXPORT_NAME = "应用版本仓库导出-{}.xlsx";
+
+ public static final String COMMAND_TEMPLATE_EXPORT_NAME = "命令模板导出-{}.xlsx";
+
+ public static final String USER_EVENT_LOG_EXPORT_NAME = "操作日志导出-{}.xlsx";
+
+ public static final String WEBHOOK_EXPORT_NAME = "webhook导出-{}.xlsx";
+
+ /**
+ * 格式导出文件名
+ *
+ * @param name name
+ * @return name
+ */
+ public static String getFileName(String name) {
+ return Strings.format(name, Dates.current(Dates.YMD_HM2));
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/constant/ExportType.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/constant/ExportType.java
new file mode 100644
index 0000000..fda8f95
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/constant/ExportType.java
@@ -0,0 +1,124 @@
+
+package cn.orionsec.ops.constant;
+
+import cn.orionsec.ops.entity.exporter.*;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.function.Supplier;
+
+@Getter
+@AllArgsConstructor
+public enum ExportType {
+
+ /**
+ * 机器信息
+ */
+ MACHINE_INFO(100,
+ "机器信息",
+ MachineInfoExportDTO.class,
+ () -> ExportConst.getFileName(ExportConst.MACHINE_EXPORT_NAME)),
+
+ /**
+ * 机器代理
+ */
+ MACHINE_PROXY(110,
+ "机器代理",
+ MachineProxyExportDTO.class,
+ () -> ExportConst.getFileName(ExportConst.MACHINE_PROXY_EXPORT_NAME)),
+
+ /**
+ * 终端日志
+ */
+ TERMINAL_LOG(120,
+ "终端日志",
+ MachineTerminalLogExportDTO.class,
+ () -> ExportConst.getFileName(ExportConst.TERMINAL_LOG_EXPORT_NAME)),
+
+ /**
+ * 机器报警记录
+ */
+ MACHINE_ALARM_HISTORY(130,
+ "机器报警记录",
+ MachineAlarmHistoryExportDTO.class,
+ () -> ExportConst.getFileName(ExportConst.MACHINE_ALARM_HISTORY_EXPORT_NAME)),
+
+ /**
+ * 应用环境
+ */
+ APP_PROFILE(200,
+ "应用环境",
+ ApplicationProfileExportDTO.class,
+ () -> ExportConst.getFileName(ExportConst.APP_PROFILE_EXPORT_NAME)),
+
+ /**
+ * 应用信息
+ */
+ APPLICATION(210,
+ "应用信息",
+ ApplicationExportDTO.class,
+ () -> ExportConst.getFileName(ExportConst.APPLICATION_EXPORT_NAME)),
+
+ /**
+ * 应用仓库
+ */
+ APP_REPOSITORY(220,
+ "应用仓库",
+ ApplicationRepositoryExportDTO.class,
+ () -> ExportConst.getFileName(ExportConst.APP_REPOSITORY_EXPORT_NAME)),
+
+ /**
+ * 命令模板
+ */
+ COMMAND_TEMPLATE(300,
+ "命令模板",
+ CommandTemplateExportDTO.class
+ , () -> ExportConst.getFileName(ExportConst.COMMAND_TEMPLATE_EXPORT_NAME)),
+
+ /**
+ * 用户操作日志
+ */
+ USER_EVENT_LOG(310,
+ "用户操作日志",
+ EventLogExportDTO.class,
+ () -> ExportConst.getFileName(ExportConst.USER_EVENT_LOG_EXPORT_NAME)),
+
+ /**
+ * 日志文件
+ */
+ TAIL_FILE(320,
+ "日志文件",
+ MachineTailFileExportDTO.class,
+ () -> ExportConst.getFileName(ExportConst.TAIL_FILE_EXPORT_NAME)),
+
+ /**
+ * webhook
+ */
+ WEBHOOK(330,
+ "webhook",
+ WebhookExportDTO.class,
+ () -> ExportConst.getFileName(ExportConst.WEBHOOK_EXPORT_NAME)),
+
+ ;
+
+ private final Integer type;
+
+ private final String label;
+
+ private final Class> dataClass;
+
+ private final Supplier nameSupplier;
+
+ public static ExportType of(Integer type) {
+ if (type == null) {
+ return null;
+ }
+ for (ExportType value : values()) {
+ if (value.type.equals(type)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/constant/ImportType.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/constant/ImportType.java
new file mode 100644
index 0000000..44637b4
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/constant/ImportType.java
@@ -0,0 +1,150 @@
+
+package cn.orionsec.ops.constant;
+
+import cn.orionsec.ops.entity.domain.*;
+import cn.orionsec.ops.entity.importer.*;
+import cn.orionsec.ops.handler.importer.validator.*;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.io.Serializable;
+
+@Getter
+@AllArgsConstructor
+public enum ImportType {
+
+ /**
+ * 机器信息
+ */
+ MACHINE_INFO(100,
+ "机器信息",
+ "/templates/import/machine-import-template.xlsx",
+ "机器导入模板.xlsx",
+ MachineValidator.INSTANCE,
+ MachineInfoImportDTO.class,
+ MachineInfoDO.class),
+
+ /**
+ * 机器代理
+ */
+ MACHINE_PROXY(110,
+ "机器代理",
+ "/templates/import/machine-proxy-import-template.xlsx",
+ "机器代理导入模板.xlsx",
+ MachineProxyValidator.INSTANCE,
+ MachineProxyImportDTO.class,
+ MachineProxyDO.class),
+
+ /**
+ * 日志文件
+ */
+ TAIL_FILE(120,
+ "日志文件",
+ "/templates/import/tail-file-import-template.xlsx",
+ "日志文件导入模板.xlsx",
+ FileTailValidator.INSTANCE,
+ MachineTailFileImportDTO.class,
+ FileTailListDO.class),
+
+ /**
+ * 应用环境
+ */
+ APP_PROFILE(200,
+ "应用环境",
+ "/templates/import/app-profile-import-template.xlsx",
+ "应用环境导入模板.xlsx",
+ ApplicationProfileValidator.INSTANCE,
+ ApplicationProfileImportDTO.class,
+ ApplicationProfileDO.class),
+
+ /**
+ * 应用信息
+ */
+ APPLICATION(210,
+ "应用信息",
+ "/templates/import/application-import-template.xlsx",
+ "应用导入模板.xlsx",
+ ApplicationValidator.INSTANCE,
+ ApplicationImportDTO.class,
+ ApplicationInfoDO.class),
+
+ /**
+ * 应用仓库
+ */
+ APP_REPOSITORY(220,
+ "版本仓库",
+ "/templates/import/app-repository-import-template.xlsx",
+ "应用仓库导入模板.xlsx",
+ ApplicationRepositoryValidator.INSTANCE,
+ ApplicationRepositoryImportDTO.class,
+ ApplicationRepositoryDO.class),
+
+ /**
+ * 命令模板
+ */
+ COMMAND_TEMPLATE(300,
+ "命令模板",
+ "/templates/import/command-template-import-template.xlsx",
+ "命令模板导入模板.xlsx",
+ CommandTemplateValidator.INSTANCE,
+ CommandTemplateImportDTO.class,
+ CommandTemplateDO.class),
+
+ /**
+ * webhook
+ */
+ WEBHOOK(310,
+ "webhook",
+ "/templates/import/webhook-import-template.xlsx",
+ "webhook导入模板.xlsx",
+ WebhookValidator.INSTANCE,
+ WebhookImportDTO.class,
+ WebhookConfigDO.class),
+
+ ;
+
+ /**
+ * 类型
+ */
+ private final Integer type;
+
+ /**
+ * 导入标签
+ */
+ private final String label;
+
+ /**
+ * 文件路径
+ */
+ private final String templatePath;
+
+ /**
+ * 下载名称
+ */
+ private final String templateName;
+
+ /**
+ * 数据验证器
+ */
+ private final DataValidator validator;
+
+ /**
+ * importClass
+ */
+ private final Class extends BaseDataImportDTO> importClass;
+
+ private final Class extends Serializable> convertClass;
+
+ public static ImportType of(Integer type) {
+ if (type == null) {
+ return null;
+ }
+ for (ImportType value : values()) {
+ if (value.type.equals(type)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/ApplicationExportDTO.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/ApplicationExportDTO.java
new file mode 100644
index 0000000..7cb6ce3
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/ApplicationExportDTO.java
@@ -0,0 +1,50 @@
+
+package cn.orionsec.ops.entity.exporter;
+
+import cn.orionsec.kit.lang.utils.convert.TypeStore;
+import cn.orionsec.kit.office.excel.annotation.ExportField;
+import cn.orionsec.kit.office.excel.annotation.ExportSheet;
+import cn.orionsec.kit.office.excel.annotation.ExportTitle;
+import cn.orionsec.ops.entity.domain.ApplicationInfoDO;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+
+@Data
+@ApiModel(value = "应用信息导出")
+@ExportTitle(title = "应用信息导出")
+@ExportSheet(name = "应用信息", height = 22, freezeHeader = true, filterHeader = true)
+public class ApplicationExportDTO {
+
+ @ApiModelProperty(value = "应用名称")
+ @ExportField(index = 0, header = "应用名称", width = 35)
+ private String name;
+
+ @ApiModelProperty(value = "唯一标识")
+ @ExportField(index = 1, header = "唯一标识", width = 30)
+ private String tag;
+
+ @ApiModelProperty(value = "应用仓库名称")
+ @ExportField(index = 2, header = "应用仓库名称", width = 30)
+ private String repoName;
+
+ @ApiModelProperty(value = "描述")
+ @ExportField(index = 3, header = "描述", width = 35, wrapText = true)
+ private String description;
+
+ @ApiModelProperty(value = "仓库id", hidden = true)
+ private Long repoId;
+
+ static {
+ TypeStore.STORE.register(ApplicationInfoDO.class, ApplicationExportDTO.class, p -> {
+ ApplicationExportDTO dto = new ApplicationExportDTO();
+ dto.setName(p.getAppName());
+ dto.setTag(p.getAppTag());
+ dto.setRepoId(p.getRepoId());
+ dto.setDescription(p.getDescription());
+ return dto;
+ });
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/ApplicationProfileExportDTO.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/ApplicationProfileExportDTO.java
new file mode 100644
index 0000000..0df9576
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/ApplicationProfileExportDTO.java
@@ -0,0 +1,49 @@
+
+package cn.orionsec.ops.entity.exporter;
+
+import cn.orionsec.kit.lang.utils.convert.TypeStore;
+import cn.orionsec.kit.office.excel.annotation.ExportField;
+import cn.orionsec.kit.office.excel.annotation.ExportSheet;
+import cn.orionsec.kit.office.excel.annotation.ExportTitle;
+import cn.orionsec.kit.office.excel.type.ExcelAlignType;
+import cn.orionsec.ops.constant.CnConst;
+import cn.orionsec.ops.constant.Const;
+import cn.orionsec.ops.entity.domain.ApplicationProfileDO;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+@ApiModel(value = "应用环境信息导出")
+@ExportTitle(title = "应用环境导出")
+@ExportSheet(name = "应用环境", height = 22, freezeHeader = true, filterHeader = true)
+public class ApplicationProfileExportDTO {
+
+ @ApiModelProperty(value = "环境名称")
+ @ExportField(index = 0, header = "环境名称", width = 30)
+ private String name;
+
+ @ApiModelProperty(value = "唯一标识")
+ @ExportField(index = 1, header = "唯一标识", width = 30)
+ private String tag;
+
+ @ApiModelProperty(value = "发布审核")
+ @ExportField(index = 2, header = "发布审核", width = 17, align = ExcelAlignType.CENTER, selectOptions = {CnConst.OPEN, CnConst.CLOSE})
+ private String releaseAudit;
+
+ @ApiModelProperty(value = "描述")
+ @ExportField(index = 3, header = "描述", width = 35, wrapText = true)
+ private String description;
+
+ static {
+ TypeStore.STORE.register(ApplicationProfileDO.class, ApplicationProfileExportDTO.class, p -> {
+ ApplicationProfileExportDTO dto = new ApplicationProfileExportDTO();
+ dto.setName(p.getProfileName());
+ dto.setTag(p.getProfileTag());
+ dto.setReleaseAudit(Const.ENABLE.equals(p.getReleaseAudit()) ? CnConst.OPEN : CnConst.CLOSE);
+ dto.setDescription(p.getDescription());
+ return dto;
+ });
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/ApplicationRepositoryExportDTO.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/ApplicationRepositoryExportDTO.java
new file mode 100644
index 0000000..7ef7c90
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/ApplicationRepositoryExportDTO.java
@@ -0,0 +1,93 @@
+
+package cn.orionsec.ops.entity.exporter;
+
+import cn.orionsec.kit.lang.utils.convert.TypeStore;
+import cn.orionsec.kit.office.excel.annotation.ExportField;
+import cn.orionsec.kit.office.excel.annotation.ExportSheet;
+import cn.orionsec.kit.office.excel.annotation.ExportTitle;
+import cn.orionsec.ops.constant.CnConst;
+import cn.orionsec.ops.constant.Const;
+import cn.orionsec.ops.constant.app.RepositoryAuthType;
+import cn.orionsec.ops.constant.app.RepositoryTokenType;
+import cn.orionsec.ops.entity.domain.ApplicationRepositoryDO;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Optional;
+
+
+@Data
+@ApiModel(value = "应用仓库导出")
+@ExportTitle(title = "应用仓库导出")
+@ExportSheet(name = "应用仓库", titleHeight = 22, headerHeight = 22, freezeHeader = true, filterHeader = true)
+public class ApplicationRepositoryExportDTO {
+
+ @ApiModelProperty(value = "名称")
+ @ExportField(index = 0, header = "名称", width = 20)
+ private String name;
+
+ @ApiModelProperty(value = "url")
+ @ExportField(index = 1, header = "url", width = 40, wrapText = true)
+ private String url;
+
+ /**
+ * @see RepositoryAuthType
+ */
+ @ApiModelProperty(value = "认证方式(密码/令牌)")
+ @ExportField(index = 2, header = "认证方式(密码/令牌)", width = 23, selectOptions = {CnConst.PASSWORD, CnConst.TOKEN})
+ private String authType;
+
+ /**
+ * @see RepositoryTokenType
+ */
+ @ApiModelProperty(value = "令牌类型")
+ @ExportField(index = 3, header = "令牌类型", width = 13, selectOptions = {Const.GITHUB, Const.GITEE, Const.GITLAB})
+ private String tokenType;
+
+ @ApiModelProperty(value = "用户名")
+ @ExportField(index = 4, header = "用户名", width = 20)
+ private String username;
+
+ @ApiModelProperty(value = "导出密码/令牌 (密文)")
+ @ExportField(index = 5, header = "导出密码/令牌", width = 21, hidden = true, wrapText = true)
+ private String encryptAuthValue;
+
+ @ApiModelProperty(value = "导入密码/令牌 (明文)")
+ @ExportField(index = 6, header = "导入密码/令牌", width = 21, wrapText = true)
+ private String importAuthValue;
+
+ @ApiModelProperty(value = "描述")
+ @ExportField(index = 7, header = "描述", width = 25, wrapText = true)
+ private String description;
+
+ static {
+ TypeStore.STORE.register(ApplicationRepositoryDO.class, ApplicationRepositoryExportDTO.class, p -> {
+ ApplicationRepositoryExportDTO dto = new ApplicationRepositoryExportDTO();
+ dto.setName(p.getRepoName());
+ dto.setUrl(p.getRepoUrl());
+ // 认证方式
+ RepositoryAuthType authType = RepositoryAuthType.of(p.getRepoAuthType());
+ if (authType != null) {
+ dto.setAuthType(authType.getLabel());
+ }
+ // 令牌类型
+ if (RepositoryAuthType.TOKEN.equals(authType)) {
+ Optional.ofNullable(p.getRepoTokenType())
+ .map(RepositoryTokenType::of)
+ .map(RepositoryTokenType::getLabel)
+ .ifPresent(dto::setTokenType);
+ if (RepositoryTokenType.GITEE.getLabel().equals(dto.getTokenType())) {
+ dto.setUsername(p.getRepoUsername());
+ }
+ dto.setEncryptAuthValue(p.getRepoPrivateToken());
+ } else {
+ dto.setUsername(p.getRepoUsername());
+ dto.setEncryptAuthValue(p.getRepoPassword());
+ }
+ dto.setDescription(p.getRepoDescription());
+ return dto;
+ });
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/CommandTemplateExportDTO.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/CommandTemplateExportDTO.java
new file mode 100644
index 0000000..026a6cd
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/CommandTemplateExportDTO.java
@@ -0,0 +1,41 @@
+
+package cn.orionsec.ops.entity.exporter;
+
+import cn.orionsec.kit.lang.utils.convert.TypeStore;
+import cn.orionsec.kit.office.excel.annotation.ExportField;
+import cn.orionsec.kit.office.excel.annotation.ExportSheet;
+import cn.orionsec.kit.office.excel.annotation.ExportTitle;
+import cn.orionsec.ops.entity.domain.CommandTemplateDO;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+@ApiModel(value = "命令模板导出")
+@ExportTitle(title = "命令模板导出")
+@ExportSheet(name = "命令模板", titleHeight = 22, headerHeight = 22, freezeHeader = true, filterHeader = true)
+public class CommandTemplateExportDTO {
+
+ @ApiModelProperty(value = "模板名称")
+ @ExportField(index = 0, header = "模板名称", width = 25)
+ private String name;
+
+ @ApiModelProperty(value = "模板命令")
+ @ExportField(index = 1, header = "模板命令", width = 80, wrapText = true)
+ private String template;
+
+ @ApiModelProperty(value = "描述")
+ @ExportField(index = 2, header = "描述", width = 35, wrapText = true)
+ private String description;
+
+ static {
+ TypeStore.STORE.register(CommandTemplateDO.class, CommandTemplateExportDTO.class, p -> {
+ CommandTemplateExportDTO dto = new CommandTemplateExportDTO();
+ dto.setName(p.getTemplateName());
+ dto.setTemplate(p.getTemplateValue());
+ dto.setDescription(p.getDescription());
+ return dto;
+ });
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/EventLogExportDTO.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/EventLogExportDTO.java
new file mode 100644
index 0000000..911f08a
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/EventLogExportDTO.java
@@ -0,0 +1,76 @@
+
+package cn.orionsec.ops.entity.exporter;
+
+import cn.orionsec.kit.lang.utils.convert.TypeStore;
+import cn.orionsec.kit.lang.utils.time.Dates;
+import cn.orionsec.kit.office.excel.annotation.ExportField;
+import cn.orionsec.kit.office.excel.annotation.ExportSheet;
+import cn.orionsec.kit.office.excel.annotation.ExportTitle;
+import cn.orionsec.kit.office.excel.type.ExcelFieldType;
+import cn.orionsec.ops.constant.event.EventClassify;
+import cn.orionsec.ops.constant.event.EventType;
+import cn.orionsec.ops.entity.domain.UserEventLogDO;
+import cn.orionsec.ops.utils.Utils;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.Optional;
+
+@Data
+@ApiModel(value = "站内信导出")
+@ExportTitle(title = "操作日志导出")
+@ExportSheet(name = "操作日志", height = 22, freezeHeader = true, filterHeader = true)
+public class EventLogExportDTO {
+
+ @ApiModelProperty(value = "用户名")
+ @ExportField(index = 0, header = "用户名", width = 15, wrapText = true)
+ private String username;
+
+ /**
+ * @see EventClassify
+ */
+ @ApiModelProperty(value = "事件分类")
+ @ExportField(index = 1, header = "事件分类", width = 17)
+ private String classify;
+
+ /**
+ * @see EventType
+ */
+ @ApiModelProperty(value = "事件类型")
+ @ExportField(index = 2, header = "事件类型", width = 22)
+ private String type;
+
+ @ApiModelProperty(value = "触发时间")
+ @ExportField(index = 3, header = "触发时间", width = 20, wrapText = true, type = ExcelFieldType.DATE, format = Dates.YMD_HMS)
+ private Date time;
+
+ @ApiModelProperty(value = "日志信息")
+ @ExportField(index = 4, header = "日志信息", width = 70, wrapText = true)
+ private String message;
+
+ @ApiModelProperty(value = "参数")
+ @ExportField(index = 5, header = "参数", width = 20, wrapText = true)
+ private String params;
+
+ static {
+ TypeStore.STORE.register(UserEventLogDO.class, EventLogExportDTO.class, p -> {
+ EventLogExportDTO dto = new EventLogExportDTO();
+ dto.setUsername(p.getUsername());
+ Optional.ofNullable(p.getEventClassify())
+ .map(EventClassify::of)
+ .map(EventClassify::getLabel)
+ .ifPresent(dto::setClassify);
+ Optional.ofNullable(p.getEventType())
+ .map(EventType::of)
+ .map(EventType::getLabel)
+ .ifPresent(dto::setType);
+ dto.setTime(p.getCreateTime());
+ dto.setMessage(Utils.cleanStainTag(p.getLogInfo()));
+ dto.setParams(p.getParamsJson());
+ return dto;
+ });
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/MachineAlarmHistoryExportDTO.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/MachineAlarmHistoryExportDTO.java
new file mode 100644
index 0000000..a9431d0
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/MachineAlarmHistoryExportDTO.java
@@ -0,0 +1,62 @@
+
+package cn.orionsec.ops.entity.exporter;
+
+import cn.orionsec.kit.lang.utils.convert.TypeStore;
+import cn.orionsec.kit.lang.utils.time.Dates;
+import cn.orionsec.kit.office.excel.annotation.ExportField;
+import cn.orionsec.kit.office.excel.annotation.ExportFont;
+import cn.orionsec.kit.office.excel.annotation.ExportSheet;
+import cn.orionsec.kit.office.excel.annotation.ExportTitle;
+import cn.orionsec.ops.constant.machine.MachineAlarmType;
+import cn.orionsec.ops.entity.domain.MachineAlarmHistoryDO;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+@ApiModel(value = "机器报警记录导出")
+@ExportTitle(title = "机器报警记录导出")
+@ExportSheet(name = "机器报警记录", height = 22, freezeHeader = true, filterHeader = true)
+public class MachineAlarmHistoryExportDTO {
+
+ @ApiModelProperty(value = "报警机器名称")
+ @ExportField(index = 0, header = "报警机器名称", width = 24, wrapText = true)
+ private String name;
+
+ @ApiModelProperty(value = "报警机器主机")
+ @ExportField(index = 1, header = "报警机器主机", width = 20, wrapText = true)
+ private String host;
+
+ /**
+ * @see MachineAlarmType
+ */
+ @ApiModelProperty(value = "报警类型 10: cpu使用率 20: 内存使用率")
+ @ExportField(index = 2, header = "报警类型", width = 18, wrapText = true)
+ private String alarmType;
+
+ @ApiModelProperty(value = "报警值")
+ @ExportField(index = 3, header = "报警值", width = 15, wrapText = true)
+ @ExportFont(color = "#F5222D")
+ private Double alarmValue;
+
+ @ApiModelProperty(value = "报警时间")
+ @ExportField(index = 4, header = "报警时间", width = 25, format = Dates.YMD_HMS)
+ private Date alarmTime;
+
+ @ApiModelProperty(value = "机器id")
+ private Long machineId;
+
+ static {
+ TypeStore.STORE.register(MachineAlarmHistoryDO.class, MachineAlarmHistoryExportDTO.class, p -> {
+ MachineAlarmHistoryExportDTO dto = new MachineAlarmHistoryExportDTO();
+ dto.setMachineId(p.getMachineId());
+ dto.setAlarmType(MachineAlarmType.of(p.getAlarmType()).getLabel());
+ dto.setAlarmValue(p.getAlarmValue());
+ dto.setAlarmTime(p.getAlarmTime());
+ return dto;
+ });
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/MachineInfoExportDTO.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/MachineInfoExportDTO.java
new file mode 100644
index 0000000..7c97b97
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/MachineInfoExportDTO.java
@@ -0,0 +1,88 @@
+
+package cn.orionsec.ops.entity.exporter;
+
+import cn.orionsec.kit.lang.utils.convert.TypeStore;
+import cn.orionsec.kit.office.excel.annotation.ExportField;
+import cn.orionsec.kit.office.excel.annotation.ExportSheet;
+import cn.orionsec.kit.office.excel.annotation.ExportTitle;
+import cn.orionsec.ops.constant.CnConst;
+import cn.orionsec.ops.constant.machine.MachineAuthType;
+import cn.orionsec.ops.entity.domain.MachineInfoDO;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+@ApiModel(value = "机器信息导出")
+@ExportTitle(title = "机器信息导出")
+@ExportSheet(name = "机器信息", height = 22, freezeHeader = true, filterHeader = true)
+public class MachineInfoExportDTO {
+
+ @ApiModelProperty(value = "id")
+ private Long id;
+
+ @ApiModelProperty(value = "机器名称")
+ @ExportField(index = 0, header = "机器名称", width = 20, wrapText = true)
+ private String name;
+
+ @ApiModelProperty(value = "唯一标识")
+ @ExportField(index = 1, header = "唯一标识", width = 20, wrapText = true)
+ private String tag;
+
+ @ApiModelProperty(value = "机器主机")
+ @ExportField(index = 2, header = "机器主机", width = 20, wrapText = true)
+ private String host;
+
+ @ApiModelProperty(value = "ssh 端口")
+ @ExportField(index = 3, header = "ssh 端口", width = 10)
+ private Integer port;
+
+ /**
+ * @see MachineAuthType
+ */
+ @ApiModelProperty(value = "认证方式")
+ @ExportField(index = 4, header = "认证方式", width = 13, selectOptions = {CnConst.PASSWORD, CnConst.SECRET_KEY})
+ private String authType;
+
+ @ApiModelProperty(value = "用户名")
+ @ExportField(index = 5, header = "用户名", width = 20, wrapText = true)
+ private String username;
+
+ @ApiModelProperty(value = "导出密码")
+ @ExportField(index = 6, header = "导出密码", hidden = true, width = 16, wrapText = true)
+ private String encryptPassword;
+
+ @ApiModelProperty(value = "导入密码")
+ @ExportField(index = 7, header = "导入密码", width = 16, wrapText = true)
+ private String importPassword;
+
+ @ApiModelProperty(value = "密钥名称")
+ @ExportField(index = 8, header = "密钥名称", width = 16, wrapText = true)
+ private String keyName;
+
+ @ApiModelProperty(value = "描述")
+ @ExportField(index = 9, header = "描述", width = 25, wrapText = true)
+ private String description;
+
+ static {
+ TypeStore.STORE.register(MachineInfoDO.class, MachineInfoExportDTO.class, p -> {
+ MachineInfoExportDTO dto = new MachineInfoExportDTO();
+ dto.setId(p.getId());
+ dto.setName(p.getMachineName());
+ dto.setTag(p.getMachineTag());
+ dto.setHost(p.getMachineHost());
+ dto.setPort(p.getSshPort());
+ dto.setUsername(p.getUsername());
+ MachineAuthType authType = MachineAuthType.of(p.getAuthType());
+ if (authType != null) {
+ dto.setAuthType(authType.getLabel());
+ }
+ if (MachineAuthType.PASSWORD.equals(authType)) {
+ dto.setEncryptPassword(p.getPassword());
+ }
+ dto.setDescription(p.getDescription());
+ return dto;
+ });
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/MachineProxyExportDTO.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/MachineProxyExportDTO.java
new file mode 100644
index 0000000..99f7618
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/MachineProxyExportDTO.java
@@ -0,0 +1,70 @@
+
+package cn.orionsec.ops.entity.exporter;
+
+import cn.orionsec.kit.lang.utils.convert.TypeStore;
+import cn.orionsec.kit.office.excel.annotation.ExportField;
+import cn.orionsec.kit.office.excel.annotation.ExportSheet;
+import cn.orionsec.kit.office.excel.annotation.ExportTitle;
+import cn.orionsec.ops.constant.Const;
+import cn.orionsec.ops.constant.machine.ProxyType;
+import cn.orionsec.ops.entity.domain.MachineProxyDO;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Optional;
+
+@Data
+@ApiModel(value = "机器代理导出")
+@ExportTitle(title = "机器代理导出")
+@ExportSheet(name = "机器代理", height = 22, freezeHeader = true, filterHeader = true)
+public class MachineProxyExportDTO {
+
+ @ApiModelProperty(value = "代理主机")
+ @ExportField(index = 0, header = "代理主机", width = 25)
+ private String host;
+
+ @ApiModelProperty(value = "代理端口")
+ @ExportField(index = 1, header = "代理端口", width = 10)
+ private Integer port;
+
+ /**
+ * @see ProxyType
+ */
+ @ApiModelProperty(value = "代理类型")
+ @ExportField(index = 2, header = "代理类型", width = 13, selectOptions = {Const.PROTOCOL_HTTP, Const.SOCKS4, Const.SOCKS5})
+ private String proxyType;
+
+ @ApiModelProperty(value = "用户名")
+ @ExportField(index = 3, header = "用户名", width = 25)
+ private String username;
+
+ @ApiModelProperty(value = "导出密码")
+ @ExportField(index = 4, header = "导出密码", hidden = true, width = 16, wrapText = true)
+ private String encryptPassword;
+
+ @ApiModelProperty(value = "导入密码")
+ @ExportField(index = 5, header = "导入密码", width = 16, wrapText = true)
+ private String importPassword;
+
+ @ApiModelProperty(value = "描述")
+ @ExportField(index = 6, header = "描述", width = 35, wrapText = true)
+ private String description;
+
+ static {
+ TypeStore.STORE.register(MachineProxyDO.class, MachineProxyExportDTO.class, p -> {
+ MachineProxyExportDTO dto = new MachineProxyExportDTO();
+ dto.setHost(p.getProxyHost());
+ dto.setPort(p.getProxyPort());
+ Optional.ofNullable(p.getProxyType())
+ .map(ProxyType::of)
+ .map(ProxyType::getLabel)
+ .ifPresent(dto::setProxyType);
+ dto.setUsername(p.getProxyUsername());
+ dto.setEncryptPassword(p.getProxyPassword());
+ dto.setDescription(p.getDescription());
+ return dto;
+ });
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/MachineTailFileExportDTO.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/MachineTailFileExportDTO.java
new file mode 100644
index 0000000..261469a
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/MachineTailFileExportDTO.java
@@ -0,0 +1,63 @@
+
+package cn.orionsec.ops.entity.exporter;
+
+import cn.orionsec.kit.lang.utils.convert.TypeStore;
+import cn.orionsec.kit.office.excel.annotation.ExportField;
+import cn.orionsec.kit.office.excel.annotation.ExportSheet;
+import cn.orionsec.kit.office.excel.annotation.ExportTitle;
+import cn.orionsec.ops.entity.domain.FileTailListDO;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+@ApiModel(value = "日志文件导出")
+@ExportTitle(title = "日志文件导出")
+@ExportSheet(name = "日志文件", titleHeight = 22, headerHeight = 22, freezeHeader = true, filterHeader = true)
+public class MachineTailFileExportDTO {
+
+ @ApiModelProperty(value = "机器名称")
+ @ExportField(index = 0, header = "机器名称", width = 20, wrapText = true)
+ private String machineName;
+
+ @ApiModelProperty(value = "机器标识")
+ @ExportField(index = 1, header = "机器标识", width = 20, wrapText = true)
+ private String machineTag;
+
+ @ApiModelProperty(value = "文件别名")
+ @ExportField(index = 2, header = "文件别名", width = 20, wrapText = true)
+ private String name;
+
+ @ApiModelProperty(value = "文件路径")
+ @ExportField(index = 3, header = "文件路径", width = 50, wrapText = true)
+ private String path;
+
+ @ApiModelProperty(value = "文件编码")
+ @ExportField(index = 4, header = "文件编码", width = 12)
+ private String charset;
+
+ @ApiModelProperty(value = "尾部偏移行")
+ @ExportField(index = 5, header = "尾部偏移行", width = 12)
+ private Integer offset;
+
+ @ApiModelProperty(value = "执行命令")
+ @ExportField(index = 6, header = "执行命令", width = 35, wrapText = true)
+ private String command;
+
+ @ApiModelProperty(value = "机器id", hidden = true)
+ private Long machineId;
+
+ static {
+ TypeStore.STORE.register(FileTailListDO.class, MachineTailFileExportDTO.class, p -> {
+ MachineTailFileExportDTO dto = new MachineTailFileExportDTO();
+ dto.setMachineId(p.getMachineId());
+ dto.setName(p.getAliasName());
+ dto.setPath(p.getFilePath());
+ dto.setCharset(p.getFileCharset());
+ dto.setOffset(p.getFileOffset());
+ dto.setCommand(p.getTailCommand());
+ return dto;
+ });
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/MachineTerminalLogExportDTO.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/MachineTerminalLogExportDTO.java
new file mode 100644
index 0000000..ce920cd
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/MachineTerminalLogExportDTO.java
@@ -0,0 +1,75 @@
+
+package cn.orionsec.ops.entity.exporter;
+
+import cn.orionsec.kit.lang.utils.convert.TypeStore;
+import cn.orionsec.kit.lang.utils.time.Dates;
+import cn.orionsec.kit.office.excel.annotation.ExportField;
+import cn.orionsec.kit.office.excel.annotation.ExportSheet;
+import cn.orionsec.kit.office.excel.annotation.ExportTitle;
+import cn.orionsec.kit.office.excel.type.ExcelFieldType;
+import cn.orionsec.ops.entity.domain.MachineTerminalLogDO;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+@ApiModel(value = "终端日志导出")
+@ExportTitle(title = "终端日志导出")
+@ExportSheet(name = "终端日志", height = 22, freezeHeader = true, filterHeader = true)
+public class MachineTerminalLogExportDTO {
+
+ @ApiModelProperty(value = "用户名")
+ @ExportField(index = 0, header = "用户名", width = 17, wrapText = true)
+ private String username;
+
+ @ApiModelProperty(value = "机器名称")
+ @ExportField(index = 1, header = "机器名称", width = 20, wrapText = true)
+ private String machineName;
+
+ @ApiModelProperty(value = "机器标识")
+ @ExportField(index = 2, header = "机器标识", width = 20, wrapText = true)
+ private String machineTag;
+
+ @ApiModelProperty(value = "机器主机")
+ @ExportField(index = 3, header = "机器主机", width = 20, wrapText = true)
+ private String machineHost;
+
+ @ApiModelProperty(value = "accessToken")
+ @ExportField(index = 4, header = "accessToken", width = 5, hidden = true, wrapText = true)
+ private String accessToken;
+
+ @ApiModelProperty(value = "建立连接时间")
+ @ExportField(index = 5, header = "建立连接时间", width = 20, wrapText = true, type = ExcelFieldType.DATE, format = Dates.YMD_HMS)
+ private Date connectedTime;
+
+ @ApiModelProperty(value = "断开连接时间")
+ @ExportField(index = 6, header = "断开连接时间", width = 20, wrapText = true, type = ExcelFieldType.DATE, format = Dates.YMD_HMS)
+ private Date disconnectedTime;
+
+ @ApiModelProperty(value = "close code")
+ @ExportField(index = 7, header = "close code", width = 11, wrapText = true)
+ private Integer closeCode;
+
+ @ApiModelProperty(value = "录屏文件路径")
+ @ExportField(index = 8, header = "录屏文件路径", width = 35, wrapText = true)
+ private String screenPath;
+
+ static {
+ TypeStore.STORE.register(MachineTerminalLogDO.class, MachineTerminalLogExportDTO.class, p -> {
+ MachineTerminalLogExportDTO dto = new MachineTerminalLogExportDTO();
+ dto.setUsername(p.getUsername());
+ dto.setMachineName(p.getMachineName());
+ dto.setMachineTag(p.getMachineTag());
+ dto.setMachineHost(p.getMachineHost());
+ dto.setAccessToken(p.getAccessToken());
+ dto.setConnectedTime(p.getConnectedTime());
+ dto.setDisconnectedTime(p.getDisconnectedTime());
+ dto.setCloseCode(p.getCloseCode());
+ dto.setScreenPath(p.getScreenPath());
+ return dto;
+ });
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/WebhookExportDTO.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/WebhookExportDTO.java
new file mode 100644
index 0000000..cb99968
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/exporter/WebhookExportDTO.java
@@ -0,0 +1,45 @@
+
+package cn.orionsec.ops.entity.exporter;
+
+import cn.orionsec.kit.lang.utils.convert.TypeStore;
+import cn.orionsec.kit.office.excel.annotation.ExportField;
+import cn.orionsec.kit.office.excel.annotation.ExportSheet;
+import cn.orionsec.kit.office.excel.annotation.ExportTitle;
+import cn.orionsec.ops.constant.webhook.WebhookType;
+import cn.orionsec.ops.entity.domain.WebhookConfigDO;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+@ApiModel(value = "webhook导出")
+@ExportTitle(title = "webhook导出")
+@ExportSheet(name = "webhook", height = 22, freezeHeader = true, filterHeader = true)
+public class WebhookExportDTO {
+
+ @ApiModelProperty(value = "名称")
+ @ExportField(index = 0, header = "名称", width = 20, wrapText = true)
+ private String name;
+
+ /**
+ * @see WebhookType
+ */
+ @ApiModelProperty(value = "类型")
+ @ExportField(index = 1, header = "类型", width = 20, wrapText = true)
+ private String type;
+
+ @ApiModelProperty(value = "url")
+ @ExportField(index = 2, header = "url", width = 80, wrapText = true)
+ private String url;
+
+ static {
+ TypeStore.STORE.register(WebhookConfigDO.class, WebhookExportDTO.class, p -> {
+ WebhookExportDTO dto = new WebhookExportDTO();
+ dto.setName(p.getWebhookName());
+ dto.setType(WebhookType.of(p.getWebhookType()).getLabel());
+ dto.setUrl(p.getWebhookUrl());
+ return dto;
+ });
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/importer/ApplicationImportDTO.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/importer/ApplicationImportDTO.java
new file mode 100644
index 0000000..0f68ae9
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/importer/ApplicationImportDTO.java
@@ -0,0 +1,56 @@
+
+package cn.orionsec.ops.entity.importer;
+
+import cn.orionsec.kit.lang.utils.convert.TypeStore;
+import cn.orionsec.kit.office.excel.annotation.ImportField;
+import cn.orionsec.ops.entity.domain.ApplicationInfoDO;
+import cn.orionsec.ops.entity.vo.data.DataImportCheckRowVO;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ApiModel(value = "应用信息导入")
+public class ApplicationImportDTO extends BaseDataImportDTO {
+
+ @ApiModelProperty(value = "应用名称")
+ @ImportField(index = 0)
+ private String name;
+
+ @ApiModelProperty(value = "唯一标识")
+ @ImportField(index = 1)
+ private String tag;
+
+ @ApiModelProperty(value = "应用仓库名称")
+ @ImportField(index = 2)
+ private String repositoryName;
+
+ @ApiModelProperty(value = "描述")
+ @ImportField(index = 3)
+ private String description;
+
+ @ApiModelProperty(value = "仓库id", hidden = true)
+ private Long repositoryId;
+
+ static {
+ TypeStore.STORE.register(ApplicationImportDTO.class, DataImportCheckRowVO.class, p -> {
+ DataImportCheckRowVO vo = new DataImportCheckRowVO();
+ vo.setSymbol(p.tag);
+ vo.setIllegalMessage(p.getIllegalMessage());
+ vo.setId(p.getId());
+ return vo;
+ });
+ TypeStore.STORE.register(ApplicationImportDTO.class, ApplicationInfoDO.class, p -> {
+ ApplicationInfoDO d = new ApplicationInfoDO();
+ d.setId(p.getId());
+ d.setAppName(p.name);
+ d.setAppTag(p.tag);
+ d.setRepoId(p.repositoryId);
+ d.setDescription(p.description);
+ return d;
+ });
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/importer/ApplicationProfileImportDTO.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/importer/ApplicationProfileImportDTO.java
new file mode 100644
index 0000000..3dff051
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/importer/ApplicationProfileImportDTO.java
@@ -0,0 +1,55 @@
+
+package cn.orionsec.ops.entity.importer;
+
+import cn.orionsec.kit.lang.utils.convert.TypeStore;
+import cn.orionsec.kit.office.excel.annotation.ImportField;
+import cn.orionsec.ops.constant.CnConst;
+import cn.orionsec.ops.constant.Const;
+import cn.orionsec.ops.entity.domain.ApplicationProfileDO;
+import cn.orionsec.ops.entity.vo.data.DataImportCheckRowVO;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ApiModel(value = "应用环境信息导入")
+public class ApplicationProfileImportDTO extends BaseDataImportDTO {
+
+ @ApiModelProperty(value = "环境名称")
+ @ImportField(index = 0)
+ private String name;
+
+ @ApiModelProperty(value = "唯一标识")
+ @ImportField(index = 1)
+ private String tag;
+
+ @ApiModelProperty(value = "发布审核")
+ @ImportField(index = 2)
+ private String releaseAudit;
+
+ @ApiModelProperty(value = "描述")
+ @ImportField(index = 3)
+ private String description;
+
+ static {
+ TypeStore.STORE.register(ApplicationProfileImportDTO.class, DataImportCheckRowVO.class, p -> {
+ DataImportCheckRowVO vo = new DataImportCheckRowVO();
+ vo.setSymbol(p.tag);
+ vo.setIllegalMessage(p.getIllegalMessage());
+ vo.setId(p.getId());
+ return vo;
+ });
+ TypeStore.STORE.register(ApplicationProfileImportDTO.class, ApplicationProfileDO.class, p -> {
+ ApplicationProfileDO d = new ApplicationProfileDO();
+ d.setId(p.getId());
+ d.setProfileName(p.name);
+ d.setProfileTag(p.tag);
+ d.setReleaseAudit(CnConst.OPEN.equals(p.releaseAudit) ? Const.ENABLE : Const.DISABLE);
+ d.setDescription(p.description);
+ return d;
+ });
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/importer/ApplicationRepositoryImportDTO.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/importer/ApplicationRepositoryImportDTO.java
new file mode 100644
index 0000000..8b34414
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/importer/ApplicationRepositoryImportDTO.java
@@ -0,0 +1,109 @@
+
+package cn.orionsec.ops.entity.importer;
+
+import cn.orionsec.kit.lang.utils.Strings;
+import cn.orionsec.kit.lang.utils.convert.TypeStore;
+import cn.orionsec.kit.office.excel.annotation.ImportField;
+import cn.orionsec.ops.constant.app.RepositoryAuthType;
+import cn.orionsec.ops.constant.app.RepositoryTokenType;
+import cn.orionsec.ops.constant.app.RepositoryType;
+import cn.orionsec.ops.entity.domain.ApplicationRepositoryDO;
+import cn.orionsec.ops.entity.vo.data.DataImportCheckRowVO;
+import cn.orionsec.ops.utils.ValueMix;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Optional;
+import java.util.function.BiConsumer;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ApiModel(value = "应用仓库导入")
+public class ApplicationRepositoryImportDTO extends BaseDataImportDTO {
+
+ @ApiModelProperty(value = "名称")
+ @ImportField(index = 0)
+ private String name;
+
+ @ApiModelProperty(value = "url")
+ @ImportField(index = 1)
+ private String url;
+
+ /**
+ * @see RepositoryAuthType
+ */
+ @ApiModelProperty(value = "认证方式")
+ @ImportField(index = 2)
+ private String authType;
+
+ /**
+ * @see RepositoryTokenType
+ */
+ @ApiModelProperty(value = "令牌类型")
+ @ImportField(index = 3)
+ private String tokenType;
+
+ @ApiModelProperty(value = "用户名")
+ @ImportField(index = 4)
+ private String username;
+
+ @ApiModelProperty(value = "导出密码/令牌 (密文)")
+ @ImportField(index = 5)
+ private String encryptAuthValue;
+
+ @ApiModelProperty(value = "导入密码/令牌 (明文)")
+ @ImportField(index = 6)
+ private String importAuthValue;
+
+ @ApiModelProperty(value = "描述")
+ @ImportField(index = 7)
+ private String description;
+
+ @ApiModelProperty(value = "密码/令牌密文解密后的明文")
+ private String decryptAuthValue;
+
+ static {
+ TypeStore.STORE.register(ApplicationRepositoryImportDTO.class, DataImportCheckRowVO.class, p -> {
+ DataImportCheckRowVO vo = new DataImportCheckRowVO();
+ vo.setSymbol(p.name);
+ vo.setIllegalMessage(p.getIllegalMessage());
+ vo.setId(p.getId());
+ return vo;
+ });
+ TypeStore.STORE.register(ApplicationRepositoryImportDTO.class, ApplicationRepositoryDO.class, p -> {
+ ApplicationRepositoryDO d = new ApplicationRepositoryDO();
+ d.setId(p.getId());
+ d.setRepoName(p.name);
+ d.setRepoDescription(p.description);
+ d.setRepoType(RepositoryType.GIT.getType());
+ d.setRepoUrl(p.url);
+ Optional.ofNullable(p.authType)
+ .map(RepositoryAuthType::of)
+ .map(RepositoryAuthType::getType)
+ .ifPresent(d::setRepoAuthType);
+ if (RepositoryAuthType.PASSWORD.getType().equals(d.getRepoAuthType()) || RepositoryTokenType.GITEE.getLabel().equals(p.tokenType)) {
+ d.setRepoUsername(p.username);
+ }
+ Optional.ofNullable(p.tokenType)
+ .map(RepositoryTokenType::of)
+ .map(RepositoryTokenType::getType)
+ .ifPresent(d::setRepoTokenType);
+ BiConsumer authValueSetter;
+ if (RepositoryAuthType.PASSWORD.getType().equals(d.getRepoAuthType())) {
+ authValueSetter = ApplicationRepositoryDO::setRepoPassword;
+ } else {
+ authValueSetter = ApplicationRepositoryDO::setRepoPrivateToken;
+ }
+ if (!Strings.isBlank(p.decryptAuthValue)) {
+ authValueSetter.accept(d, ValueMix.encrypt(p.decryptAuthValue));
+ }
+ if (!Strings.isBlank(p.importAuthValue)) {
+ authValueSetter.accept(d, ValueMix.encrypt(p.importAuthValue));
+ }
+ return d;
+ });
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/importer/BaseDataImportDTO.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/importer/BaseDataImportDTO.java
new file mode 100644
index 0000000..d0f0481
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/importer/BaseDataImportDTO.java
@@ -0,0 +1,19 @@
+
+package cn.orionsec.ops.entity.importer;
+
+import lombok.Data;
+
+@Data
+public class BaseDataImportDTO {
+
+ /**
+ * 非法信息 非法操作
+ */
+ private String illegalMessage;
+
+ /**
+ * 数据id 更新操作
+ */
+ private Long id;
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/importer/CommandTemplateImportDTO.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/importer/CommandTemplateImportDTO.java
new file mode 100644
index 0000000..a666b30
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/importer/CommandTemplateImportDTO.java
@@ -0,0 +1,49 @@
+
+package cn.orionsec.ops.entity.importer;
+
+import cn.orionsec.kit.lang.utils.convert.TypeStore;
+import cn.orionsec.kit.office.excel.annotation.ImportField;
+import cn.orionsec.ops.entity.domain.CommandTemplateDO;
+import cn.orionsec.ops.entity.vo.data.DataImportCheckRowVO;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ApiModel(value = "命令模板导入")
+public class CommandTemplateImportDTO extends BaseDataImportDTO {
+
+ @ApiModelProperty(value = "模板名称")
+ @ImportField(index = 0)
+ private String name;
+
+ @ApiModelProperty(value = "模板命令")
+ @ImportField(index = 1)
+ private String template;
+
+ @ApiModelProperty(value = "描述")
+ @ImportField(index = 2)
+ private String description;
+
+ static {
+ TypeStore.STORE.register(CommandTemplateImportDTO.class, DataImportCheckRowVO.class, p -> {
+ DataImportCheckRowVO vo = new DataImportCheckRowVO();
+ vo.setSymbol(p.name);
+ vo.setIllegalMessage(p.getIllegalMessage());
+ vo.setId(p.getId());
+ return vo;
+ });
+ TypeStore.STORE.register(CommandTemplateImportDTO.class, CommandTemplateDO.class, p -> {
+ CommandTemplateDO d = new CommandTemplateDO();
+ d.setId(p.getId());
+ d.setTemplateName(p.name);
+ d.setTemplateValue(p.template);
+ d.setDescription(p.description);
+ return d;
+ });
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/importer/DataImportDTO.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/importer/DataImportDTO.java
new file mode 100644
index 0000000..71a8afd
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/importer/DataImportDTO.java
@@ -0,0 +1,50 @@
+
+package cn.orionsec.ops.entity.importer;
+
+import cn.orionsec.ops.constant.ImportType;
+import cn.orionsec.ops.entity.vo.data.DataImportCheckVO;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+public class DataImportDTO {
+
+ /**
+ * token
+ */
+ private String importToken;
+
+ /**
+ * 类型
+ *
+ * @see ImportType
+ */
+ private Integer type;
+
+ /**
+ * 导入数据 json
+ */
+ private String data;
+
+ /**
+ * 检查数据
+ */
+ private DataImportCheckVO check;
+
+ /**
+ * 导入用户id 手动
+ */
+ private Long userId;
+
+ /**
+ * 导入用户名称 手动
+ */
+ private String userName;
+
+ /**
+ * 导入时间 手动
+ */
+ private Date importTime;
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/importer/MachineInfoImportDTO.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/importer/MachineInfoImportDTO.java
new file mode 100644
index 0000000..7fb284b
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/importer/MachineInfoImportDTO.java
@@ -0,0 +1,106 @@
+
+package cn.orionsec.ops.entity.importer;
+
+import cn.orionsec.kit.lang.utils.Strings;
+import cn.orionsec.kit.lang.utils.convert.TypeStore;
+import cn.orionsec.kit.office.excel.annotation.ImportField;
+import cn.orionsec.ops.constant.machine.MachineAuthType;
+import cn.orionsec.ops.entity.domain.MachineInfoDO;
+import cn.orionsec.ops.entity.vo.data.DataImportCheckRowVO;
+import cn.orionsec.ops.utils.ValueMix;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Optional;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ApiModel(value = "机器信息导入")
+public class MachineInfoImportDTO extends BaseDataImportDTO {
+
+ @ApiModelProperty(value = "机器名称")
+ @ImportField(index = 0)
+ private String name;
+
+ @ApiModelProperty(value = "唯一标识")
+ @ImportField(index = 1)
+ private String tag;
+
+ @ApiModelProperty(value = "机器主机")
+ @ImportField(index = 2)
+ private String host;
+
+ @ApiModelProperty(value = "ssh 端口")
+ @ImportField(index = 3)
+ private Integer port;
+
+ /**
+ * @see MachineAuthType
+ */
+ @ApiModelProperty(value = "认证方式")
+ @ImportField(index = 4)
+ private String authType;
+
+ @ApiModelProperty(value = "用户名")
+ @ImportField(index = 5)
+ private String username;
+
+ @ApiModelProperty(value = "密码 (密文)")
+ @ImportField(index = 6)
+ private String encryptPassword;
+
+ @ApiModelProperty(value = "导入密码 (明文)")
+ @ImportField(index = 7)
+ private String importPassword;
+
+ @ApiModelProperty(value = "密钥名称")
+ @ImportField(index = 8)
+ private String keyName;
+
+ @ApiModelProperty(value = "描述")
+ @ImportField(index = 9)
+ private String description;
+
+ @ApiModelProperty(value = "密码密文解密后的明文", hidden = true)
+ private String decryptPassword;
+
+ @ApiModelProperty(value = "密钥id", hidden = true)
+ private Long keyId;
+
+ static {
+ TypeStore.STORE.register(MachineInfoImportDTO.class, DataImportCheckRowVO.class, p -> {
+ DataImportCheckRowVO vo = new DataImportCheckRowVO();
+ vo.setSymbol(p.tag);
+ vo.setIllegalMessage(p.getIllegalMessage());
+ vo.setId(p.getId());
+ return vo;
+ });
+ TypeStore.STORE.register(MachineInfoImportDTO.class, MachineInfoDO.class, p -> {
+ MachineInfoDO d = new MachineInfoDO();
+ d.setId(p.getId());
+ d.setMachineName(p.name);
+ d.setMachineTag(p.tag);
+ d.setMachineHost(p.host);
+ d.setSshPort(p.port);
+ d.setKeyId(p.keyId);
+ Optional.ofNullable(p.authType)
+ .map(MachineAuthType::of)
+ .map(MachineAuthType::getType)
+ .ifPresent(d::setAuthType);
+ d.setUsername(p.username);
+ if (MachineAuthType.PASSWORD.getType().equals(d.getAuthType())) {
+ if (!Strings.isBlank(p.decryptPassword)) {
+ d.setPassword(ValueMix.encrypt(p.decryptPassword));
+ }
+ if (!Strings.isBlank(p.importPassword)) {
+ d.setPassword(ValueMix.encrypt(p.importPassword));
+ }
+ }
+ d.setDescription(p.description);
+ return d;
+ });
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/importer/MachineProxyImportDTO.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/importer/MachineProxyImportDTO.java
new file mode 100644
index 0000000..c04693d
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/importer/MachineProxyImportDTO.java
@@ -0,0 +1,86 @@
+
+package cn.orionsec.ops.entity.importer;
+
+import cn.orionsec.kit.lang.utils.Strings;
+import cn.orionsec.kit.lang.utils.convert.TypeStore;
+import cn.orionsec.kit.office.excel.annotation.ImportField;
+import cn.orionsec.ops.constant.machine.ProxyType;
+import cn.orionsec.ops.entity.domain.MachineProxyDO;
+import cn.orionsec.ops.entity.vo.data.DataImportCheckRowVO;
+import cn.orionsec.ops.utils.ValueMix;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Optional;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ApiModel(value = "机器代理导入")
+public class MachineProxyImportDTO extends BaseDataImportDTO {
+
+ @ApiModelProperty(value = "代理主机")
+ @ImportField(index = 0)
+ private String host;
+
+ @ApiModelProperty(value = "代理端口")
+ @ImportField(index = 1)
+ private Integer port;
+
+ /**
+ * @see ProxyType
+ */
+ @ApiModelProperty(value = "代理类型")
+ @ImportField(index = 2)
+ private String proxyType;
+
+ @ApiModelProperty(value = "用户名")
+ @ImportField(index = 3)
+ private String username;
+
+ @ApiModelProperty(value = "导出密码 (密文)")
+ @ImportField(index = 4)
+ private String encryptPassword;
+
+ @ApiModelProperty(value = "导入密码 (明文)")
+ @ImportField(index = 5)
+ private String importPassword;
+
+ @ApiModelProperty(value = "描述")
+ @ImportField(index = 6)
+ private String description;
+
+ @ApiModelProperty(value = "密码密文解密后的明文", hidden = true)
+ private String decryptPassword;
+
+ static {
+ TypeStore.STORE.register(MachineProxyImportDTO.class, DataImportCheckRowVO.class, p -> {
+ DataImportCheckRowVO vo = new DataImportCheckRowVO();
+ vo.setSymbol(p.host);
+ vo.setIllegalMessage(p.getIllegalMessage());
+ vo.setId(p.getId());
+ return vo;
+ });
+ TypeStore.STORE.register(MachineProxyImportDTO.class, MachineProxyDO.class, p -> {
+ MachineProxyDO d = new MachineProxyDO();
+ d.setId(p.getId());
+ d.setProxyHost(p.host);
+ d.setProxyPort(p.port);
+ d.setProxyUsername(p.username);
+ if (!Strings.isBlank(p.decryptPassword)) {
+ d.setProxyPassword(ValueMix.encrypt(p.decryptPassword));
+ }
+ if (!Strings.isBlank(p.importPassword)) {
+ d.setProxyPassword(ValueMix.encrypt(p.importPassword));
+ }
+ Optional.ofNullable(p.proxyType)
+ .map(ProxyType::of)
+ .map(ProxyType::getType)
+ .ifPresent(d::setProxyType);
+ d.setDescription(p.description);
+ return d;
+ });
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/importer/MachineTailFileImportDTO.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/importer/MachineTailFileImportDTO.java
new file mode 100644
index 0000000..cbf0e24
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/importer/MachineTailFileImportDTO.java
@@ -0,0 +1,73 @@
+
+package cn.orionsec.ops.entity.importer;
+
+import cn.orionsec.kit.lang.utils.convert.TypeStore;
+import cn.orionsec.kit.office.excel.annotation.ImportField;
+import cn.orionsec.ops.constant.Const;
+import cn.orionsec.ops.constant.tail.FileTailMode;
+import cn.orionsec.ops.entity.domain.FileTailListDO;
+import cn.orionsec.ops.entity.vo.data.DataImportCheckRowVO;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ApiModel(value = "机器代理导入")
+public class MachineTailFileImportDTO extends BaseDataImportDTO {
+
+ @ApiModelProperty(value = "机器标识")
+ @ImportField(index = 1)
+ private String machineTag;
+
+ @ApiModelProperty(value = "别名")
+ @ImportField(index = 2)
+ private String name;
+
+ @ApiModelProperty(value = "文件路径")
+ @ImportField(index = 3)
+ private String path;
+
+ @ApiModelProperty(value = "文件编码")
+ @ImportField(index = 4)
+ private String charset;
+
+ @ApiModelProperty(value = "尾部偏移行")
+ @ImportField(index = 5)
+ private Integer offset;
+
+ @ApiModelProperty(value = "执行命令")
+ @ImportField(index = 6)
+ private String command;
+
+ @ApiModelProperty(value = "机器id", hidden = true)
+ private Long machineId;
+
+ static {
+ TypeStore.STORE.register(MachineTailFileImportDTO.class, DataImportCheckRowVO.class, p -> {
+ DataImportCheckRowVO vo = new DataImportCheckRowVO();
+ vo.setSymbol(p.name);
+ vo.setIllegalMessage(p.getIllegalMessage());
+ vo.setId(p.getId());
+ return vo;
+ });
+ TypeStore.STORE.register(MachineTailFileImportDTO.class, FileTailListDO.class, p -> {
+ FileTailListDO d = new FileTailListDO();
+ d.setId(p.getId());
+ d.setMachineId(p.machineId);
+ d.setAliasName(p.name);
+ d.setFilePath(p.path);
+ d.setFileCharset(p.charset);
+ d.setFileOffset(p.offset);
+ d.setTailCommand(p.command);
+ if (Const.HOST_MACHINE_ID.equals(p.machineId)) {
+ d.setTailMode(FileTailMode.TRACKER.getMode());
+ } else {
+ d.setTailMode(FileTailMode.TAIL.getMode());
+ }
+ return d;
+ });
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/importer/WebhookImportDTO.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/importer/WebhookImportDTO.java
new file mode 100644
index 0000000..cb0b9bf
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/entity/importer/WebhookImportDTO.java
@@ -0,0 +1,57 @@
+
+package cn.orionsec.ops.entity.importer;
+
+import cn.orionsec.kit.lang.utils.convert.TypeStore;
+import cn.orionsec.kit.office.excel.annotation.ImportField;
+import cn.orionsec.ops.constant.webhook.WebhookType;
+import cn.orionsec.ops.entity.domain.WebhookConfigDO;
+import cn.orionsec.ops.entity.vo.data.DataImportCheckRowVO;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Optional;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ApiModel(value = "webhook 导入")
+public class WebhookImportDTO extends BaseDataImportDTO {
+
+ @ApiModelProperty(value = "名称")
+ @ImportField(index = 0)
+ private String name;
+
+ /**
+ * @see WebhookType
+ */
+ @ApiModelProperty(value = "类型")
+ @ImportField(index = 1)
+ private String type;
+
+ @ApiModelProperty(value = "url")
+ @ImportField(index = 2)
+ private String url;
+
+ static {
+ TypeStore.STORE.register(WebhookImportDTO.class, DataImportCheckRowVO.class, p -> {
+ DataImportCheckRowVO vo = new DataImportCheckRowVO();
+ vo.setSymbol(p.name);
+ vo.setIllegalMessage(p.getIllegalMessage());
+ vo.setId(p.getId());
+ return vo;
+ });
+ TypeStore.STORE.register(WebhookImportDTO.class, WebhookConfigDO.class, p -> {
+ WebhookConfigDO d = new WebhookConfigDO();
+ d.setId(p.getId());
+ d.setWebhookName(p.name);
+ d.setWebhookUrl(p.url);
+ Optional.ofNullable(p.type)
+ .map(WebhookType::of)
+ .map(WebhookType::getType)
+ .ifPresent(d::setWebhookType);
+ return d;
+ });
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/AbstractDataExporter.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/AbstractDataExporter.java
new file mode 100644
index 0000000..1b753b8
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/AbstractDataExporter.java
@@ -0,0 +1,105 @@
+
+package cn.orionsec.ops.handler.exporter;
+
+import cn.orionsec.kit.lang.utils.Strings;
+import cn.orionsec.kit.lang.utils.io.FileWriters;
+import cn.orionsec.kit.lang.utils.io.Files1;
+import cn.orionsec.kit.office.excel.writer.exporting.ExcelExport;
+import cn.orionsec.kit.web.servlet.web.Servlets;
+import cn.orionsec.ops.constant.ExportType;
+import cn.orionsec.ops.constant.event.EventKeys;
+import cn.orionsec.ops.constant.system.SystemEnvAttr;
+import cn.orionsec.ops.entity.request.data.DataExportRequest;
+import cn.orionsec.ops.utils.Currents;
+import cn.orionsec.ops.utils.EventParamsHolder;
+import cn.orionsec.ops.utils.PathBuilders;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.List;
+
+public abstract class AbstractDataExporter implements IDataExporter {
+
+ /**
+ * 导出类型
+ */
+ protected final ExportType exportType;
+
+ /**
+ * 请求参数
+ */
+ protected final DataExportRequest request;
+
+ /**
+ * http response
+ */
+ protected final HttpServletResponse response;
+
+ protected ExcelExport exporter;
+
+ public AbstractDataExporter(ExportType exportType, DataExportRequest request, HttpServletResponse response) {
+ this.exportType = exportType;
+ this.request = request;
+ this.response = response;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void doExport() throws IOException {
+ // 查询数据
+ List exportList = this.queryData();
+ // 初始化导出器
+ this.exporter = new ExcelExport((Class) exportType.getDataClass()).init();
+ exporter.addRows(exportList);
+ // 写入到 workbook
+ this.writeWorkbook();
+ // 设置日志参数
+ this.setEventParams();
+ }
+
+ /**
+ * 查询数据
+ *
+ * @return rows
+ */
+ protected abstract List queryData();
+
+ /**
+ * 写入 workbook
+ *
+ * @throws IOException IOException
+ */
+ protected void writeWorkbook() throws IOException {
+ // 设置 http 响应头
+ Servlets.setAttachmentHeader(response, exportType.getNameSupplier().get());
+ // 写入 workbook 到 byte
+ ByteArrayOutputStream store = new ByteArrayOutputStream();
+ String password = request.getProtectPassword();
+ if (!Strings.isBlank(password)) {
+ exporter.write(store, password);
+ } else {
+ exporter.write(store);
+ }
+ // 设置 http 返回
+ byte[] excelData = store.toByteArray();
+ response.getOutputStream().write(excelData);
+ // 保存至本地
+ String exportPath = PathBuilders.getExportDataJsonPath(Currents.getUserId(), exportType.getType(), Strings.def(password));
+ String path = Files1.getPath(SystemEnvAttr.LOG_PATH.getValue(), exportPath);
+ FileWriters.write(path, excelData);
+ }
+
+ /**
+ * 设置日志参数
+ */
+ protected void setEventParams() {
+ // 设置日志参数
+ EventParamsHolder.addParam(EventKeys.EXPORT_PASSWORD, request.getExportPassword());
+ EventParamsHolder.addParam(EventKeys.PROTECT, request.getProtectPassword() != null);
+ EventParamsHolder.addParam(EventKeys.COUNT, exporter.getRows());
+ EventParamsHolder.addParam(EventKeys.EXPORT_TYPE, exportType.getType());
+ EventParamsHolder.addParam(EventKeys.LABEL, exportType.getLabel());
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/AppProfileDataExporter.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/AppProfileDataExporter.java
new file mode 100644
index 0000000..8ffa585
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/AppProfileDataExporter.java
@@ -0,0 +1,30 @@
+
+package cn.orionsec.ops.handler.exporter;
+
+import cn.orionsec.kit.lang.utils.convert.Converts;
+import cn.orionsec.kit.spring.SpringHolder;
+import cn.orionsec.ops.constant.ExportType;
+import cn.orionsec.ops.dao.ApplicationProfileDAO;
+import cn.orionsec.ops.entity.domain.ApplicationProfileDO;
+import cn.orionsec.ops.entity.exporter.ApplicationProfileExportDTO;
+import cn.orionsec.ops.entity.request.data.DataExportRequest;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+public class AppProfileDataExporter extends AbstractDataExporter {
+
+ private static final ApplicationProfileDAO applicationProfileDAO = SpringHolder.getBean(ApplicationProfileDAO.class);
+
+ public AppProfileDataExporter(DataExportRequest request, HttpServletResponse response) {
+ super(ExportType.APP_PROFILE, request, response);
+ }
+
+ @Override
+ protected List queryData() {
+ // 查询数据
+ List profileList = applicationProfileDAO.selectList(null);
+ return Converts.toList(profileList, ApplicationProfileExportDTO.class);
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/AppRepositoryDataExporter.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/AppRepositoryDataExporter.java
new file mode 100644
index 0000000..6840442
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/AppRepositoryDataExporter.java
@@ -0,0 +1,35 @@
+
+package cn.orionsec.ops.handler.exporter;
+
+import cn.orionsec.kit.lang.utils.convert.Converts;
+import cn.orionsec.kit.spring.SpringHolder;
+import cn.orionsec.ops.constant.Const;
+import cn.orionsec.ops.constant.ExportType;
+import cn.orionsec.ops.dao.ApplicationRepositoryDAO;
+import cn.orionsec.ops.entity.domain.ApplicationRepositoryDO;
+import cn.orionsec.ops.entity.exporter.ApplicationRepositoryExportDTO;
+import cn.orionsec.ops.entity.request.data.DataExportRequest;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+public class AppRepositoryDataExporter extends AbstractDataExporter {
+
+ private static final ApplicationRepositoryDAO applicationRepositoryDAO = SpringHolder.getBean(ApplicationRepositoryDAO.class);
+
+ public AppRepositoryDataExporter(DataExportRequest request, HttpServletResponse response) {
+ super(ExportType.APP_REPOSITORY, request, response);
+ }
+
+ @Override
+ protected List queryData() {
+ // 查询数据
+ List repoList = applicationRepositoryDAO.selectList(null);
+ List exportList = Converts.toList(repoList, ApplicationRepositoryExportDTO.class);
+ if (!Const.ENABLE.equals(request.getExportPassword())) {
+ exportList.forEach(s -> s.setEncryptAuthValue(null));
+ }
+ return exportList;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/ApplicationDataExporter.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/ApplicationDataExporter.java
new file mode 100644
index 0000000..fe806f2
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/ApplicationDataExporter.java
@@ -0,0 +1,56 @@
+
+package cn.orionsec.ops.handler.exporter;
+
+import cn.orionsec.kit.lang.utils.convert.Converts;
+import cn.orionsec.kit.spring.SpringHolder;
+import cn.orionsec.ops.constant.ExportType;
+import cn.orionsec.ops.dao.ApplicationInfoDAO;
+import cn.orionsec.ops.dao.ApplicationRepositoryDAO;
+import cn.orionsec.ops.entity.domain.ApplicationInfoDO;
+import cn.orionsec.ops.entity.domain.ApplicationRepositoryDO;
+import cn.orionsec.ops.entity.exporter.ApplicationExportDTO;
+import cn.orionsec.ops.entity.request.data.DataExportRequest;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+public class ApplicationDataExporter extends AbstractDataExporter {
+
+ private static final ApplicationInfoDAO applicationInfoDAO = SpringHolder.getBean(ApplicationInfoDAO.class);
+
+ private static final ApplicationRepositoryDAO applicationRepositoryDAO = SpringHolder.getBean(ApplicationRepositoryDAO.class);
+
+ public ApplicationDataExporter(DataExportRequest request, HttpServletResponse response) {
+ super(ExportType.APPLICATION, request, response);
+ }
+
+ @Override
+ protected List queryData() {
+ // 查询数据
+ List appList = applicationInfoDAO.selectList(null);
+ List exportList = Converts.toList(appList, ApplicationExportDTO.class);
+ // 仓库名称
+ List repoIdList = appList.stream()
+ .map(ApplicationInfoDO::getRepoId)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ if (!repoIdList.isEmpty()) {
+ List repoNameList = applicationRepositoryDAO.selectNameByIdList(repoIdList);
+ // 设置仓库名称
+ for (ApplicationExportDTO export : exportList) {
+ Long repoId = export.getRepoId();
+ if (repoId == null) {
+ continue;
+ }
+ repoNameList.stream()
+ .filter(s -> s.getId().equals(repoId))
+ .findFirst()
+ .ifPresent(s -> export.setRepoName(s.getRepoName()));
+ }
+ }
+ return exportList;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/CommandTemplateDataExporter.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/CommandTemplateDataExporter.java
new file mode 100644
index 0000000..480fce5
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/CommandTemplateDataExporter.java
@@ -0,0 +1,30 @@
+
+package cn.orionsec.ops.handler.exporter;
+
+import cn.orionsec.kit.lang.utils.convert.Converts;
+import cn.orionsec.kit.spring.SpringHolder;
+import cn.orionsec.ops.constant.ExportType;
+import cn.orionsec.ops.dao.CommandTemplateDAO;
+import cn.orionsec.ops.entity.domain.CommandTemplateDO;
+import cn.orionsec.ops.entity.exporter.CommandTemplateExportDTO;
+import cn.orionsec.ops.entity.request.data.DataExportRequest;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+
+public class CommandTemplateDataExporter extends AbstractDataExporter {
+
+ private static final CommandTemplateDAO commandTemplateDAO = SpringHolder.getBean(CommandTemplateDAO.class);
+
+ public CommandTemplateDataExporter(DataExportRequest request, HttpServletResponse response) {
+ super(ExportType.COMMAND_TEMPLATE, request, response);
+ }
+
+ @Override
+ protected List queryData() {
+ List templateList = commandTemplateDAO.selectList(null);
+ return Converts.toList(templateList, CommandTemplateExportDTO.class);
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/IDataExporter.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/IDataExporter.java
new file mode 100644
index 0000000..8d56f08
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/IDataExporter.java
@@ -0,0 +1,59 @@
+
+package cn.orionsec.ops.handler.exporter;
+
+import cn.orionsec.kit.lang.utils.Exceptions;
+import cn.orionsec.ops.constant.ExportType;
+import cn.orionsec.ops.constant.MessageConst;
+import cn.orionsec.ops.entity.request.data.DataExportRequest;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+
+public interface IDataExporter {
+
+ /**
+ * 执行导出
+ *
+ * @throws IOException IOException
+ */
+ void doExport() throws IOException;
+
+ /**
+ * 创建数据导出器
+ *
+ * @param exportType 导出类型
+ * @param request request
+ * @param response response
+ * @return exporter
+ */
+ static IDataExporter create(ExportType exportType, DataExportRequest request, HttpServletResponse response) {
+ switch (exportType) {
+ case MACHINE_INFO:
+ return new MachineInfoDataExporter(request, response);
+ case MACHINE_PROXY:
+ return new MachineProxyDataExporter(request, response);
+ case TERMINAL_LOG:
+ return new TerminalLogDataExporter(request, response);
+ case MACHINE_ALARM_HISTORY:
+ return new MachineAlarmHistoryDataExporter(request, response);
+ case APP_PROFILE:
+ return new AppProfileDataExporter(request, response);
+ case APPLICATION:
+ return new ApplicationDataExporter(request, response);
+ case APP_REPOSITORY:
+ return new AppRepositoryDataExporter(request, response);
+ case COMMAND_TEMPLATE:
+ return new CommandTemplateDataExporter(request, response);
+ case USER_EVENT_LOG:
+ return new UserEventLogDataExporter(request, response);
+ case TAIL_FILE:
+ return new TailFileDataExporter(request, response);
+ case WEBHOOK:
+ return new WebhookDataExporter(request, response);
+ default:
+ throw Exceptions.argument(MessageConst.UNKNOWN_EXPORT_TYPE);
+ }
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/MachineAlarmHistoryDataExporter.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/MachineAlarmHistoryDataExporter.java
new file mode 100644
index 0000000..36ec7b3
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/MachineAlarmHistoryDataExporter.java
@@ -0,0 +1,67 @@
+
+package cn.orionsec.ops.handler.exporter;
+
+import cn.orionsec.kit.lang.utils.convert.Converts;
+import cn.orionsec.kit.spring.SpringHolder;
+import cn.orionsec.ops.constant.ExportType;
+import cn.orionsec.ops.constant.event.EventKeys;
+import cn.orionsec.ops.dao.MachineAlarmHistoryDAO;
+import cn.orionsec.ops.dao.MachineInfoDAO;
+import cn.orionsec.ops.entity.domain.MachineAlarmHistoryDO;
+import cn.orionsec.ops.entity.domain.MachineInfoDO;
+import cn.orionsec.ops.entity.exporter.MachineAlarmHistoryExportDTO;
+import cn.orionsec.ops.entity.request.data.DataExportRequest;
+import cn.orionsec.ops.utils.EventParamsHolder;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+public class MachineAlarmHistoryDataExporter extends AbstractDataExporter {
+
+ private static final MachineInfoDAO machineInfoDAO = SpringHolder.getBean(MachineInfoDAO.class);
+
+ private static final MachineAlarmHistoryDAO machineAlarmHistoryDAO = SpringHolder.getBean(MachineAlarmHistoryDAO.class);
+
+ public MachineAlarmHistoryDataExporter(DataExportRequest request, HttpServletResponse response) {
+ super(ExportType.MACHINE_ALARM_HISTORY, request, response);
+ }
+
+ @Override
+ protected List queryData() {
+ // 查询数据
+ Long machineId = request.getMachineId();
+ LambdaQueryWrapper wrapper = new LambdaQueryWrapper()
+ .eq(Objects.nonNull(machineId), MachineAlarmHistoryDO::getMachineId, machineId)
+ .orderByDesc(MachineAlarmHistoryDO::getCreateTime);
+ List history = machineAlarmHistoryDAO.selectList(wrapper);
+ List historyList = Converts.toList(history, MachineAlarmHistoryExportDTO.class);
+ // 查询机器名称
+ List machineIdList = historyList.stream()
+ .map(MachineAlarmHistoryExportDTO::getMachineId)
+ .distinct()
+ .collect(Collectors.toList());
+ if (!machineIdList.isEmpty()) {
+ List machines = machineInfoDAO.selectNameByIdList(machineIdList);
+ for (MachineAlarmHistoryExportDTO record : historyList) {
+ machines.stream()
+ .filter(s -> s.getId().equals(record.getMachineId()))
+ .findFirst()
+ .ifPresent(m -> {
+ record.setName(m.getMachineName());
+ record.setHost(m.getMachineHost());
+ });
+ }
+ }
+ return historyList;
+ }
+
+ @Override
+ protected void setEventParams() {
+ super.setEventParams();
+ EventParamsHolder.addParam(EventKeys.MACHINE_ID, request.getMachineId());
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/MachineInfoDataExporter.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/MachineInfoDataExporter.java
new file mode 100644
index 0000000..43c7e93
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/MachineInfoDataExporter.java
@@ -0,0 +1,59 @@
+
+package cn.orionsec.ops.handler.exporter;
+
+import cn.orionsec.kit.lang.utils.convert.Converts;
+import cn.orionsec.kit.spring.SpringHolder;
+import cn.orionsec.ops.constant.Const;
+import cn.orionsec.ops.constant.ExportType;
+import cn.orionsec.ops.dao.MachineInfoDAO;
+import cn.orionsec.ops.dao.MachineSecretKeyDAO;
+import cn.orionsec.ops.entity.domain.MachineInfoDO;
+import cn.orionsec.ops.entity.domain.MachineSecretKeyDO;
+import cn.orionsec.ops.entity.exporter.MachineInfoExportDTO;
+import cn.orionsec.ops.entity.request.data.DataExportRequest;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+public class MachineInfoDataExporter extends AbstractDataExporter {
+
+ private static final MachineInfoDAO machineInfoDAO = SpringHolder.getBean(MachineInfoDAO.class);
+
+ private static final MachineSecretKeyDAO machineSecretKeyDAO = SpringHolder.getBean(MachineSecretKeyDAO.class);
+
+ public MachineInfoDataExporter(DataExportRequest request, HttpServletResponse response) {
+ super(ExportType.MACHINE_INFO, request, response);
+ }
+
+ @Override
+ protected List queryData() {
+ // 查询机器信息
+ List machineList = machineInfoDAO.selectList(null);
+ List exportList = Converts.toList(machineList, MachineInfoExportDTO.class);
+ // 查询密钥
+ List keyIdList = machineList.stream()
+ .map(MachineInfoDO::getKeyId)
+ .filter(Objects::nonNull)
+ .distinct()
+ .collect(Collectors.toList());
+ if (!keyIdList.isEmpty()) {
+ // 查询密钥
+ Map keyNameMap = machineSecretKeyDAO.selectBatchIds(keyIdList)
+ .stream()
+ .collect(Collectors.toMap(MachineSecretKeyDO::getId, MachineSecretKeyDO::getKeyName));
+ // 设置密钥名称
+ for (MachineInfoExportDTO machine : exportList) {
+ machine.setKeyName(keyNameMap.get(machine.getId()));
+ }
+ }
+ // 设置密码
+ if (!Const.ENABLE.equals(request.getExportPassword())) {
+ exportList.forEach(s -> s.setEncryptPassword(null));
+ }
+ return exportList;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/MachineProxyDataExporter.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/MachineProxyDataExporter.java
new file mode 100644
index 0000000..88a9d8f
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/MachineProxyDataExporter.java
@@ -0,0 +1,35 @@
+
+package cn.orionsec.ops.handler.exporter;
+
+import cn.orionsec.kit.lang.utils.convert.Converts;
+import cn.orionsec.kit.spring.SpringHolder;
+import cn.orionsec.ops.constant.Const;
+import cn.orionsec.ops.constant.ExportType;
+import cn.orionsec.ops.dao.MachineProxyDAO;
+import cn.orionsec.ops.entity.domain.MachineProxyDO;
+import cn.orionsec.ops.entity.exporter.MachineProxyExportDTO;
+import cn.orionsec.ops.entity.request.data.DataExportRequest;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+public class MachineProxyDataExporter extends AbstractDataExporter {
+
+ private static final MachineProxyDAO machineProxyDAO = SpringHolder.getBean(MachineProxyDAO.class);
+
+ public MachineProxyDataExporter(DataExportRequest request, HttpServletResponse response) {
+ super(ExportType.MACHINE_PROXY, request, response);
+ }
+
+ @Override
+ protected List queryData() {
+ // 查询数据
+ List proxyList = machineProxyDAO.selectList(null);
+ List exportList = Converts.toList(proxyList, MachineProxyExportDTO.class);
+ if (!Const.ENABLE.equals(request.getExportPassword())) {
+ exportList.forEach(s -> s.setEncryptPassword(null));
+ }
+ return exportList;
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/TailFileDataExporter.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/TailFileDataExporter.java
new file mode 100644
index 0000000..cc8fa01
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/TailFileDataExporter.java
@@ -0,0 +1,70 @@
+
+package cn.orionsec.ops.handler.exporter;
+
+import cn.orionsec.kit.lang.utils.convert.Converts;
+import cn.orionsec.kit.spring.SpringHolder;
+import cn.orionsec.ops.constant.ExportType;
+import cn.orionsec.ops.constant.event.EventKeys;
+import cn.orionsec.ops.dao.FileTailListDAO;
+import cn.orionsec.ops.dao.MachineInfoDAO;
+import cn.orionsec.ops.entity.domain.FileTailListDO;
+import cn.orionsec.ops.entity.domain.MachineInfoDO;
+import cn.orionsec.ops.entity.exporter.MachineTailFileExportDTO;
+import cn.orionsec.ops.entity.request.data.DataExportRequest;
+import cn.orionsec.ops.utils.EventParamsHolder;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+public class TailFileDataExporter extends AbstractDataExporter {
+
+ private static final MachineInfoDAO machineInfoDAO = SpringHolder.getBean(MachineInfoDAO.class);
+
+ private static final FileTailListDAO fileTailListDAO = SpringHolder.getBean(FileTailListDAO.class);
+
+ public TailFileDataExporter(DataExportRequest request, HttpServletResponse response) {
+ super(ExportType.TAIL_FILE, request, response);
+ }
+
+ @Override
+ protected List queryData() {
+ // 查询数据
+ Long queryMachineId = request.getMachineId();
+ LambdaQueryWrapper wrapper = new LambdaQueryWrapper()
+ .eq(Objects.nonNull(queryMachineId), FileTailListDO::getMachineId, queryMachineId);
+ List fileList = fileTailListDAO.selectList(wrapper);
+ List exportList = Converts.toList(fileList, MachineTailFileExportDTO.class);
+ // 机器名称
+ List machineIdList = fileList.stream()
+ .map(FileTailListDO::getMachineId)
+ .collect(Collectors.toList());
+ if (!machineIdList.isEmpty()) {
+ List machineNameList = machineInfoDAO.selectNameByIdList(machineIdList);
+ // 设置机器名称
+ for (MachineTailFileExportDTO export : exportList) {
+ Long machineId = export.getMachineId();
+ if (machineId == null) {
+ continue;
+ }
+ machineNameList.stream()
+ .filter(s -> s.getId().equals(machineId))
+ .findFirst()
+ .ifPresent(s -> {
+ export.setMachineName(s.getMachineName());
+ export.setMachineTag(s.getMachineTag());
+ });
+ }
+ }
+ return exportList;
+ }
+
+ @Override
+ protected void setEventParams() {
+ super.setEventParams();
+ EventParamsHolder.addParam(EventKeys.MACHINE_ID, request.getMachineId());
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/TerminalLogDataExporter.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/TerminalLogDataExporter.java
new file mode 100644
index 0000000..e9ccf1e
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/TerminalLogDataExporter.java
@@ -0,0 +1,44 @@
+
+package cn.orionsec.ops.handler.exporter;
+
+import cn.orionsec.kit.lang.utils.convert.Converts;
+import cn.orionsec.kit.spring.SpringHolder;
+import cn.orionsec.ops.constant.ExportType;
+import cn.orionsec.ops.constant.event.EventKeys;
+import cn.orionsec.ops.dao.MachineTerminalLogDAO;
+import cn.orionsec.ops.entity.domain.MachineTerminalLogDO;
+import cn.orionsec.ops.entity.exporter.MachineTerminalLogExportDTO;
+import cn.orionsec.ops.entity.request.data.DataExportRequest;
+import cn.orionsec.ops.utils.EventParamsHolder;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+import java.util.Objects;
+
+public class TerminalLogDataExporter extends AbstractDataExporter {
+
+ private static final MachineTerminalLogDAO machineTerminalLogDAO = SpringHolder.getBean(MachineTerminalLogDAO.class);
+
+ public TerminalLogDataExporter(DataExportRequest request, HttpServletResponse response) {
+ super(ExportType.TERMINAL_LOG, request, response);
+ }
+
+ @Override
+ protected List queryData() {
+ // 查询数据
+ Long machineId = request.getMachineId();
+ LambdaQueryWrapper wrapper = new LambdaQueryWrapper()
+ .eq(Objects.nonNull(machineId), MachineTerminalLogDO::getMachineId, machineId)
+ .orderByDesc(MachineTerminalLogDO::getCreateTime);
+ List terminalList = machineTerminalLogDAO.selectList(wrapper);
+ return Converts.toList(terminalList, MachineTerminalLogExportDTO.class);
+ }
+
+ @Override
+ protected void setEventParams() {
+ super.setEventParams();
+ EventParamsHolder.addParam(EventKeys.MACHINE_ID, request.getMachineId());
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/UserEventLogDataExporter.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/UserEventLogDataExporter.java
new file mode 100644
index 0000000..3c639ed
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/UserEventLogDataExporter.java
@@ -0,0 +1,58 @@
+
+package cn.orionsec.ops.handler.exporter;
+
+import cn.orionsec.kit.lang.utils.convert.Converts;
+import cn.orionsec.kit.spring.SpringHolder;
+import cn.orionsec.ops.constant.Const;
+import cn.orionsec.ops.constant.ExportType;
+import cn.orionsec.ops.constant.event.EventKeys;
+import cn.orionsec.ops.dao.UserEventLogDAO;
+import cn.orionsec.ops.entity.domain.UserEventLogDO;
+import cn.orionsec.ops.entity.exporter.EventLogExportDTO;
+import cn.orionsec.ops.entity.request.data.DataExportRequest;
+import cn.orionsec.ops.utils.Currents;
+import cn.orionsec.ops.utils.EventParamsHolder;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+import java.util.Objects;
+
+public class UserEventLogDataExporter extends AbstractDataExporter {
+
+ private static final UserEventLogDAO userEventLogDAO = SpringHolder.getBean(UserEventLogDAO.class);
+
+ public UserEventLogDataExporter(DataExportRequest request, HttpServletResponse response) {
+ super(ExportType.USER_EVENT_LOG, request, response);
+ // 设置用户id
+ if (Currents.isAdministrator()) {
+ if (Const.ENABLE.equals(request.getOnlyMyself())) {
+ request.setUserId(Currents.getUserId());
+ }
+ } else {
+ request.setUserId(Currents.getUserId());
+ }
+ }
+
+ @Override
+ protected List queryData() {
+ // 查询数据
+ Long userId = request.getUserId();
+ Integer classify = request.getClassify();
+ LambdaQueryWrapper wrapper = new LambdaQueryWrapper()
+ .eq(UserEventLogDO::getExecResult, Const.ENABLE)
+ .eq(Objects.nonNull(userId), UserEventLogDO::getUserId, userId)
+ .eq(Objects.nonNull(classify), UserEventLogDO::getEventClassify, classify)
+ .orderByDesc(UserEventLogDO::getCreateTime);
+ List logList = userEventLogDAO.selectList(wrapper);
+ return Converts.toList(logList, EventLogExportDTO.class);
+ }
+
+ @Override
+ protected void setEventParams() {
+ super.setEventParams();
+ EventParamsHolder.addParam(EventKeys.USER_ID, request.getUserId());
+ EventParamsHolder.addParam(EventKeys.CLASSIFY, request.getClassify());
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/WebhookDataExporter.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/WebhookDataExporter.java
new file mode 100644
index 0000000..ac5d14a
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/exporter/WebhookDataExporter.java
@@ -0,0 +1,43 @@
+
+package cn.orionsec.ops.handler.exporter;
+
+import cn.orionsec.kit.lang.utils.convert.Converts;
+import cn.orionsec.kit.spring.SpringHolder;
+import cn.orionsec.ops.constant.ExportType;
+import cn.orionsec.ops.constant.event.EventKeys;
+import cn.orionsec.ops.dao.WebhookConfigDAO;
+import cn.orionsec.ops.entity.domain.WebhookConfigDO;
+import cn.orionsec.ops.entity.exporter.WebhookExportDTO;
+import cn.orionsec.ops.entity.request.data.DataExportRequest;
+import cn.orionsec.ops.utils.EventParamsHolder;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+import java.util.Objects;
+
+public class WebhookDataExporter extends AbstractDataExporter {
+
+ private static final WebhookConfigDAO webhookConfigDAO = SpringHolder.getBean(WebhookConfigDAO.class);
+
+ public WebhookDataExporter(DataExportRequest request, HttpServletResponse response) {
+ super(ExportType.WEBHOOK, request, response);
+ }
+
+ @Override
+ protected List queryData() {
+ // 查询数据
+ Integer type = request.getType();
+ LambdaQueryWrapper wrapper = new LambdaQueryWrapper()
+ .eq(Objects.nonNull(type), WebhookConfigDO::getWebhookType, type);
+ List list = webhookConfigDAO.selectList(wrapper);
+ return Converts.toList(list, WebhookExportDTO.class);
+ }
+
+ @Override
+ protected void setEventParams() {
+ super.setEventParams();
+ EventParamsHolder.addParam(EventKeys.TYPE, request.getType());
+ }
+
+}
diff --git a/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/importer/checker/AbstractDataChecker.java b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/importer/checker/AbstractDataChecker.java
new file mode 100644
index 0000000..6eb1629
--- /dev/null
+++ b/orion-ops-api/orion-ops-data/src/main/java/cn/orionsec/ops/handler/importer/checker/AbstractDataChecker.java
@@ -0,0 +1,261 @@
+
+package cn.orionsec.ops.handler.importer.checker;
+
+import cn.orionsec.kit.lang.id.UUIds;
+import cn.orionsec.kit.lang.utils.Exceptions;
+import cn.orionsec.kit.lang.utils.Strings;
+import cn.orionsec.kit.lang.utils.collect.Lists;
+import cn.orionsec.kit.lang.utils.collect.Maps;
+import cn.orionsec.kit.lang.utils.convert.Converts;
+import cn.orionsec.kit.office.excel.Excels;
+import cn.orionsec.kit.office.excel.reader.ExcelBeanReader;
+import cn.orionsec.kit.spring.SpringHolder;
+import cn.orionsec.ops.constant.ImportType;
+import cn.orionsec.ops.constant.KeyConst;
+import cn.orionsec.ops.entity.importer.BaseDataImportDTO;
+import cn.orionsec.ops.entity.importer.DataImportDTO;
+import cn.orionsec.ops.entity.vo.data.DataImportCheckRowVO;
+import cn.orionsec.ops.entity.vo.data.DataImportCheckVO;
+import cn.orionsec.ops.utils.Currents;
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.springframework.data.redis.core.RedisTemplate;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+
+public abstract class AbstractDataChecker implements IDataChecker {
+
+ private static final RedisTemplate redisTemplate = SpringHolder.getBean("redisTemplate");
+
+ /**
+ * 导入类型
+ */
+ private final ImportType importType;
+
+ /**
+ * workbook
+ */
+ private final Workbook workbook;
+
+ public AbstractDataChecker(ImportType importType, Workbook workbook) {
+ this.importType = importType;
+ this.workbook = workbook;
+ }
+
+ @Override
+ public DataImportCheckVO doCheck() {
+ // 解析数据
+ List rows;
+ try {
+ rows = this.parserImportWorkbook();
+ } catch (Exception e) {
+ throw Exceptions.parse(e);
+ } finally {
+ Excels.close(workbook);
+ }
+ // 检查数据
+ return this.checkImportData(rows);
+ }
+
+ /**
+ * 检查数据
+ *
+ * @param rows rows
+ * @return check
+ */
+ protected abstract DataImportCheckVO checkImportData(List rows);
+
+ /**
+ * 解析导入数据
+ *
+ * @return rows
+ */
+ @SuppressWarnings("unchecked")
+ protected List parserImportWorkbook() {
+ ExcelBeanReader reader = new ExcelBeanReader(workbook, workbook.getSheetAt(0), (Class) importType.getImportClass());
+ return reader.skip(2)
+ .read()
+ .getRows();
+ }
+
+ /**
+ * 验证对象合法性
+ *
+ * @param rows rows
+ */
+ protected void validImportRows(List rows) {
+ for (T row : rows) {
+ try {
+ importType.getValidator().validData(row);
+ } catch (Exception e) {
+ row.setIllegalMessage(e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * 获取导入行已存在的数据
+ *
+ * @param rows rows
+ * @param rowKeyGetter rowKeyGetter
+ * @param mapper mapper
+ * @param domainKeyGetter domainKeyGetter
+ * @return present domain
+ */
+ protected List getImportRowsPresentValues(List rows,
+ Function rowKeyGetter,
+ BaseMapper mapper,
+ SFunction domainKeyGetter) {
+ List> symbolList = rows.stream()
+ .filter(s -> Objects.isNull(s.getIllegalMessage()))
+ .map(rowKeyGetter)
+ .collect(Collectors.toList());
+ if (symbolList.isEmpty()) {
+ return Lists.empty();
+ } else {
+ LambdaQueryWrapper