🔨 批量执行.
This commit is contained in:
14
README.md
14
README.md
@@ -2,7 +2,8 @@
|
|||||||
<img style="margin-right: 8px;" src="https://bjuimg.obs.cn-north-4.myhuaweicloud.com/images/2024/2/27/8c687ef1-5711-4a93-9db0-79c010af7902.png" width="32px" height="32px"/> orion-ops-pro 是什么
|
<img style="margin-right: 8px;" src="https://bjuimg.obs.cn-north-4.myhuaweicloud.com/images/2024/2/27/8c687ef1-5711-4a93-9db0-79c010af7902.png" width="32px" height="32px"/> orion-ops-pro 是什么
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
`orion-ops-pro` 一款开箱即用的一站式智能运维平台, 提供了资产管理、资产授权、Web终端、WebSftp、角色管理、系统管理等功能。致力于简化运维团队的治理工作。它是根据 `orion-ops`
|
`orion-ops-pro` 一款开箱即用的一站式智能运维管理平台,
|
||||||
|
提供了资产管理、资产授权、Web终端、WebSftp、角色管理、系统管理等功能。致力于简化运维团队的治理工作。它是根据 `orion-ops`
|
||||||
的产品思路完全重构的一套系统, 重新设计了架构并优化交互逻辑, 操作更快捷友好。
|
的产品思路完全重构的一套系统, 重新设计了架构并优化交互逻辑, 操作更快捷友好。
|
||||||
|
|
||||||
<p style="text-align: left">
|
<p style="text-align: left">
|
||||||
@@ -32,11 +33,12 @@
|
|||||||
github: https://github.com/lijiahangmax/orion-ops-pro
|
github: https://github.com/lijiahangmax/orion-ops-pro
|
||||||
gitee: https://gitee.com/lijiahangmax/orion-ops-pro
|
gitee: https://gitee.com/lijiahangmax/orion-ops-pro
|
||||||
文档: https://lijiahangmax.gitee.io/orion-ops-pro/#/
|
文档: https://lijiahangmax.gitee.io/orion-ops-pro/#/
|
||||||
demo: http://101.43.254.243:1081/#/
|
demo: http://101.43.254.243:1081/
|
||||||
|
|
||||||
演示账号: `admin`
|
演示账号: `admin`
|
||||||
演示密码: `admin`
|
演示密码: `admin`
|
||||||
留个小星星再走吧⭐
|
⭐ 体验后可以点一下 `star` 这对我很重要
|
||||||
|
📞 合作/功能定制请联系底部 备注: '定制'
|
||||||
|
|
||||||
## 特性
|
## 特性
|
||||||
|
|
||||||
@@ -46,10 +48,9 @@ demo: http://101.43.254.243:1081/#/
|
|||||||
* 权限控制: 全面管理用户角色, 支持动态菜单配置和强制下线等功能。
|
* 权限控制: 全面管理用户角色, 支持动态菜单配置和强制下线等功能。
|
||||||
* 在线终端: 提供便捷的在线 Web 终端服务, 支持快捷命令、自定义快捷键和主题风格。
|
* 在线终端: 提供便捷的在线 Web 终端服务, 支持快捷命令、自定义快捷键和主题风格。
|
||||||
* 文件管理: 实现远程主机大文件的批量上传、下载和在线编辑等操作。
|
* 文件管理: 实现远程主机大文件的批量上传、下载和在线编辑等操作。
|
||||||
|
* 批量操作: 支持远程主机批量执行 shell 命令。
|
||||||
* 可扩展性: 前后端代码规范统一、代码质量高、健壮且易于阅读和扩展。
|
* 可扩展性: 前后端代码规范统一、代码质量高、健壮且易于阅读和扩展。
|
||||||
|
|
||||||
[comment]: <> ( FIXME * 批量操作: 支持远程主机批量执行命令 以及 批量执行上传文件)
|
|
||||||
|
|
||||||
[comment]: <> ( FIXME * 调度任务: 维护 cron 表达式, 定时执行主机命令)
|
[comment]: <> ( FIXME * 调度任务: 维护 cron 表达式, 定时执行主机命令)
|
||||||
|
|
||||||
[comment]: <> ( FIXME * 功能强大: 命令批量执行, 任务定时调度, 远程日志查看, 操作日志全记录等)
|
[comment]: <> ( FIXME * 功能强大: 命令批量执行, 任务定时调度, 远程日志查看, 操作日志全记录等)
|
||||||
@@ -112,7 +113,8 @@ roadmap: https://lijiahangmax.gitee.io/orion-ops-pro/#/about/roadmap
|
|||||||
<img src="https://bjuimg.obs.cn-north-4.myhuaweicloud.com/images/2024/2/27/4f1c4e77-8e36-45a3-8be6-9da5387bb96e.jpg" alt="wx" width="298px" height="398px"/>
|
<img src="https://bjuimg.obs.cn-north-4.myhuaweicloud.com/images/2024/2/27/4f1c4e77-8e36-45a3-8be6-9da5387bb96e.jpg" alt="wx" width="298px" height="398px"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
📧 微信添加备注: ops
|
📧 咨询问题微信备注: ops
|
||||||
|
📧 合作/功能定制备注: 合作
|
||||||
|
|
||||||
## 支持一下
|
## 支持一下
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
<img style="margin-right: 8px;" src="./assert/logo.svg" width="32px" height="32px"/> orion-ops-pro 是什么
|
<img style="margin-right: 8px;" src="./assert/logo.svg" width="32px" height="32px"/> orion-ops-pro 是什么
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
`orion-ops-pro` 一款开箱即用的一站式智能运维平台, 提供了资产管理、资产授权、Web终端、WebSftp、角色管理、系统管理等功能。致力于简化运维团队的治理工作。它是根据 `orion-ops`
|
`orion-ops-pro` 一款开箱即用的一站式智能运维管理平台,
|
||||||
|
提供了资产管理、资产授权、Web终端、WebSftp、角色管理、系统管理等功能。致力于简化运维团队的治理工作。它是根据 `orion-ops`
|
||||||
的产品思路完全重构的一套系统, 重新设计了架构并优化交互逻辑, 操作更快捷友好。
|
的产品思路完全重构的一套系统, 重新设计了架构并优化交互逻辑, 操作更快捷友好。
|
||||||
|
|
||||||
<p style="text-align: left">
|
<p style="text-align: left">
|
||||||
@@ -32,11 +33,12 @@
|
|||||||
github: https://github.com/lijiahangmax/orion-ops-pro
|
github: https://github.com/lijiahangmax/orion-ops-pro
|
||||||
gitee: https://gitee.com/lijiahangmax/orion-ops-pro
|
gitee: https://gitee.com/lijiahangmax/orion-ops-pro
|
||||||
文档: https://lijiahangmax.gitee.io/orion-ops-pro/#/
|
文档: https://lijiahangmax.gitee.io/orion-ops-pro/#/
|
||||||
demo: http://101.43.254.243:1081/#/
|
demo: http://101.43.254.243:1081/
|
||||||
|
|
||||||
演示账号: `admin`
|
演示账号: `admin`
|
||||||
演示密码: `admin`
|
演示密码: `admin`
|
||||||
留个小星星再走吧⭐
|
⭐ 体验后可以点一下 `star` 这对我很重要
|
||||||
|
📞 合作/功能定制请联系底部 备注: '合作'
|
||||||
|
|
||||||
## 特性
|
## 特性
|
||||||
|
|
||||||
@@ -46,10 +48,9 @@ demo: http://101.43.254.243:1081/#/
|
|||||||
* 权限控制: 全面管理用户角色, 支持动态菜单配置和强制下线等功能。
|
* 权限控制: 全面管理用户角色, 支持动态菜单配置和强制下线等功能。
|
||||||
* 在线终端: 提供便捷的在线 Web 终端服务, 支持快捷命令、自定义快捷键和主题风格。
|
* 在线终端: 提供便捷的在线 Web 终端服务, 支持快捷命令、自定义快捷键和主题风格。
|
||||||
* 文件管理: 实现远程主机大文件的批量上传、下载和在线编辑等操作。
|
* 文件管理: 实现远程主机大文件的批量上传、下载和在线编辑等操作。
|
||||||
|
* 批量操作: 支持远程主机批量执行 shell 命令。
|
||||||
* 可扩展性: 前后端代码规范统一、代码质量高、健壮且易于阅读和扩展。
|
* 可扩展性: 前后端代码规范统一、代码质量高、健壮且易于阅读和扩展。
|
||||||
|
|
||||||
[comment]: <> ( FIXME * 批量操作: 支持远程主机批量执行命令 以及 批量执行上传文件)
|
|
||||||
|
|
||||||
[comment]: <> ( FIXME * 调度任务: 维护 cron 表达式, 定时执行主机命令)
|
[comment]: <> ( FIXME * 调度任务: 维护 cron 表达式, 定时执行主机命令)
|
||||||
|
|
||||||
[comment]: <> ( FIXME * 功能强大: 命令批量执行, 任务定时调度, 远程日志查看, 操作日志全记录等)
|
[comment]: <> ( FIXME * 功能强大: 命令批量执行, 任务定时调度, 远程日志查看, 操作日志全记录等)
|
||||||
@@ -112,7 +113,8 @@ roadmap: https://lijiahangmax.gitee.io/orion-ops-pro/#/about/roadmap
|
|||||||
<img src="./assert/img/wx.jpg" alt="wx" width="298px" height="398px"/>
|
<img src="./assert/img/wx.jpg" alt="wx" width="298px" height="398px"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
📧 微信添加备注: ops
|
📧 咨询问题微信备注: ops
|
||||||
|
📧 合作/功能定制备注: 合作
|
||||||
|
|
||||||
## 支持一下
|
## 支持一下
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,15 @@
|
|||||||
⚡ 注意: 应用不支持跨版本升级, 可以进行多次升级
|
⚡ 注意: 应用不支持跨版本升级, 可以进行多次升级
|
||||||
|
|
||||||
|
## v1.0.2
|
||||||
|
|
||||||
|
> sql 脚本
|
||||||
|
|
||||||
|
```sql
|
||||||
|
ALTER TABLE `host_connect_log`
|
||||||
|
MODIFY COLUMN `start_time` datetime(3) NULL DEFAULT NULL COMMENT '开始时间' AFTER `token`,
|
||||||
|
MODIFY COLUMN `end_time` datetime(3) NULL DEFAULT NULL COMMENT '结束时间' AFTER `start_time`;
|
||||||
|
```
|
||||||
|
|
||||||
## v1.0.1
|
## v1.0.1
|
||||||
|
|
||||||
> sql 脚本
|
> sql 脚本
|
||||||
|
|||||||
@@ -75,6 +75,5 @@ public class ExecController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO tail log
|
// TODO tail log
|
||||||
// TODO parameterSchema 存储
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,10 @@ public class ExecLogDO extends BaseDO {
|
|||||||
@TableField("command")
|
@TableField("command")
|
||||||
private String command;
|
private String command;
|
||||||
|
|
||||||
|
@Schema(description = "参数 schema")
|
||||||
|
@TableField("parameter_schema")
|
||||||
|
private String parameterSchema;
|
||||||
|
|
||||||
@Schema(description = "超时时间")
|
@Schema(description = "超时时间")
|
||||||
@TableField("timeout")
|
@TableField("timeout")
|
||||||
private Integer timeout;
|
private Integer timeout;
|
||||||
|
|||||||
@@ -38,6 +38,10 @@ public class ExecCommandRequest {
|
|||||||
@Schema(description = "执行参数")
|
@Schema(description = "执行参数")
|
||||||
private String parameter;
|
private String parameter;
|
||||||
|
|
||||||
|
@NotBlank
|
||||||
|
@Schema(description = "参数 schema")
|
||||||
|
private String parameterSchema;
|
||||||
|
|
||||||
@NotEmpty
|
@NotEmpty
|
||||||
@Schema(description = "执行主机")
|
@Schema(description = "执行主机")
|
||||||
private List<Long> hostIdList;
|
private List<Long> hostIdList;
|
||||||
|
|||||||
@@ -40,6 +40,9 @@ public class ExecLogVO implements Serializable {
|
|||||||
@Schema(description = "执行命令")
|
@Schema(description = "执行命令")
|
||||||
private String command;
|
private String command;
|
||||||
|
|
||||||
|
@Schema(description = "参数 schema")
|
||||||
|
private String parameterSchema;
|
||||||
|
|
||||||
@Schema(description = "超时时间")
|
@Schema(description = "超时时间")
|
||||||
private Integer timeout;
|
private Integer timeout;
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.orion.ops.module.asset.handler.host.exec.handler;
|
|||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.orion.lang.exception.AuthenticationException;
|
import com.orion.lang.exception.AuthenticationException;
|
||||||
|
import com.orion.lang.exception.ConnectionRuntimeException;
|
||||||
import com.orion.lang.exception.argument.InvalidArgumentException;
|
import com.orion.lang.exception.argument.InvalidArgumentException;
|
||||||
import com.orion.lang.support.timeout.TimeoutChecker;
|
import com.orion.lang.support.timeout.TimeoutChecker;
|
||||||
import com.orion.lang.utils.Strings;
|
import com.orion.lang.utils.Strings;
|
||||||
@@ -82,7 +83,6 @@ public class ExecCommandHandler implements IExecCommandHandler {
|
|||||||
}
|
}
|
||||||
// 执行回调
|
// 执行回调
|
||||||
if (this.interrupted) {
|
if (this.interrupted) {
|
||||||
// TODO 测试
|
|
||||||
// 中断执行
|
// 中断执行
|
||||||
this.updateStatus(ExecHostStatusEnum.INTERRUPTED, null);
|
this.updateStatus(ExecHostStatusEnum.INTERRUPTED, null);
|
||||||
} else if (ex != null) {
|
} else if (ex != null) {
|
||||||
@@ -192,6 +192,8 @@ public class ExecCommandHandler implements IExecCommandHandler {
|
|||||||
message = "执行超时";
|
message = "执行超时";
|
||||||
} else if (ex instanceof InvalidArgumentException) {
|
} else if (ex instanceof InvalidArgumentException) {
|
||||||
message = ex.getMessage();
|
message = ex.getMessage();
|
||||||
|
} else if (ex instanceof ConnectionRuntimeException) {
|
||||||
|
message = "连接失败";
|
||||||
} else if (ex instanceof AuthenticationException) {
|
} else if (ex instanceof AuthenticationException) {
|
||||||
message = "认证失败";
|
message = "认证失败";
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -102,6 +102,7 @@ public class ExecServiceImpl implements ExecService {
|
|||||||
.source(ExecSourceEnum.BATCH.name())
|
.source(ExecSourceEnum.BATCH.name())
|
||||||
.description(Strings.ifBlank(request.getDescription(), Strings.retain(command, 60) + Const.OMIT))
|
.description(Strings.ifBlank(request.getDescription(), Strings.retain(command, 60) + Const.OMIT))
|
||||||
.command(command)
|
.command(command)
|
||||||
|
.parameterSchema(request.getParameterSchema())
|
||||||
.timeout(request.getTimeout())
|
.timeout(request.getTimeout())
|
||||||
.status(ExecStatusEnum.WAITING.name())
|
.status(ExecStatusEnum.WAITING.name())
|
||||||
.build();
|
.build();
|
||||||
@@ -159,6 +160,7 @@ public class ExecServiceImpl implements ExecService {
|
|||||||
.timeout(execLog.getTimeout())
|
.timeout(execLog.getTimeout())
|
||||||
.command(execLog.getCommand())
|
.command(execLog.getCommand())
|
||||||
.parameter(hostLogs.get(0).getParameter())
|
.parameter(hostLogs.get(0).getParameter())
|
||||||
|
.parameterSchema(execLog.getParameterSchema())
|
||||||
.hostIdList(hostIdList)
|
.hostIdList(hostIdList)
|
||||||
.build();
|
.build();
|
||||||
return this.execCommand(request);
|
return this.execCommand(request);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
<result column="source_id" property="sourceId"/>
|
<result column="source_id" property="sourceId"/>
|
||||||
<result column="description" property="description"/>
|
<result column="description" property="description"/>
|
||||||
<result column="command" property="command"/>
|
<result column="command" property="command"/>
|
||||||
|
<result column="parameter_schema" property="parameterSchema"/>
|
||||||
<result column="timeout" property="timeout"/>
|
<result column="timeout" property="timeout"/>
|
||||||
<result column="status" property="status"/>
|
<result column="status" property="status"/>
|
||||||
<result column="start_time" property="startTime"/>
|
<result column="start_time" property="startTime"/>
|
||||||
@@ -24,7 +25,7 @@
|
|||||||
|
|
||||||
<!-- 通用查询结果列 -->
|
<!-- 通用查询结果列 -->
|
||||||
<sql id="Base_Column_List">
|
<sql id="Base_Column_List">
|
||||||
id, user_id, username, source, source_id, description, command, timeout, status, start_time, finish_time, create_time, update_time, creator, updater, deleted
|
id, user_id, username, source, source_id, description, command, parameter_schema, timeout, status, start_time, finish_time, create_time, update_time, creator, updater, deleted
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
@@ -33,9 +33,9 @@ export interface ExecCommandResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行命令
|
* 批量执行命令
|
||||||
*/
|
*/
|
||||||
export function execCommand(request: ExecCommandRequest) {
|
export function batchExecCommand(request: ExecCommandRequest) {
|
||||||
return axios.post<ExecCommandResponse>('/asset/exec/exec-command', request);
|
return axios.post<ExecCommandResponse>('/asset/exec/exec-command', request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,10 +48,11 @@
|
|||||||
// 内置参数提示
|
// 内置参数提示
|
||||||
builtinsParams.forEach(s => {
|
builtinsParams.forEach(s => {
|
||||||
suggestions.push({
|
suggestions.push({
|
||||||
label: s.name,
|
label: '_' + s.name,
|
||||||
kind: monaco.languages.CompletionItemKind.Function,
|
kind: monaco.languages.CompletionItemKind.Variable,
|
||||||
insertText: `@{{ ${s.name} }}`,
|
insertText: `@{{ ${s.name} }}`,
|
||||||
detail: s.desc || '',
|
detail: s.desc || '',
|
||||||
|
documentation: s.desc || '',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// 命令参数提示
|
// 命令参数提示
|
||||||
@@ -60,10 +61,11 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
suggestions.push({
|
suggestions.push({
|
||||||
label: s.name,
|
label: '_' + s.name,
|
||||||
kind: monaco.languages.CompletionItemKind.Function,
|
kind: monaco.languages.CompletionItemKind.Field,
|
||||||
insertText: `@{{ ${s.name} }}`,
|
insertText: `@{{ ${s.name} }}`,
|
||||||
detail: s.desc || '',
|
detail: s.desc || '',
|
||||||
|
documentation: s.desc || '',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -108,6 +108,9 @@ export function formatDuration(start: number, end?: number): string {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
const duration = (end - start) / 1000;
|
const duration = (end - start) / 1000;
|
||||||
|
if (duration < 1) {
|
||||||
|
return `${duration.toFixed(1)}s`;
|
||||||
|
}
|
||||||
const minutes = Math.floor(duration / 60);
|
const minutes = Math.floor(duration / 60);
|
||||||
const seconds = Math.floor(duration % 60);
|
const seconds = Math.floor(duration % 60);
|
||||||
let result = '';
|
let result = '';
|
||||||
@@ -188,7 +191,7 @@ export const resetObject = (obj: any, ignore: string[] = []) => {
|
|||||||
export const objectTruthKeyCount = (obj: any, ignore: string[] = []) => {
|
export const objectTruthKeyCount = (obj: any, ignore: string[] = []) => {
|
||||||
return Object.keys(obj)
|
return Object.keys(obj)
|
||||||
.filter(s => !ignore.includes(s))
|
.filter(s => !ignore.includes(s))
|
||||||
.reduce(function(acc, curr) {
|
.reduce(function (acc, curr) {
|
||||||
const currVal = obj[curr];
|
const currVal = obj[curr];
|
||||||
return acc + ~~(currVal !== undefined && currVal !== null && currVal?.length !== 0 && currVal !== '');
|
return acc + ~~(currVal !== undefined && currVal !== null && currVal?.length !== 0 && currVal !== '');
|
||||||
}, 0);
|
}, 0);
|
||||||
@@ -221,7 +224,7 @@ export function detectZoom() {
|
|||||||
* 获取唯一的 UUID
|
* 获取唯一的 UUID
|
||||||
*/
|
*/
|
||||||
export function getUUID() {
|
export function getUUID() {
|
||||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
||||||
const r = Math.random() * 16 | 0;
|
const r = Math.random() * 16 | 0;
|
||||||
const v = c === 'x' ? r : (r & 0x3 | 0x8);
|
const v = c === 'x' ? r : (r & 0x3 | 0x8);
|
||||||
return v.toString(16);
|
return v.toString(16);
|
||||||
|
|||||||
@@ -19,10 +19,6 @@
|
|||||||
placeholder="请选择主机"
|
placeholder="请选择主机"
|
||||||
allow-clear />
|
allow-clear />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<!-- 主机地址 -->
|
|
||||||
<a-form-item field="hostAddress" label="主机地址">
|
|
||||||
<a-input v-model="formModel.hostAddress" placeholder="请输入主机地址" allow-clear />
|
|
||||||
</a-form-item>
|
|
||||||
<!-- 状态 -->
|
<!-- 状态 -->
|
||||||
<a-form-item field="status" label="状态">
|
<a-form-item field="status" label="状态">
|
||||||
<a-select v-model="formModel.status"
|
<a-select v-model="formModel.status"
|
||||||
@@ -30,6 +26,10 @@
|
|||||||
:options="toOptions(connectStatusKey)"
|
:options="toOptions(connectStatusKey)"
|
||||||
allow-clear />
|
allow-clear />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<!-- 主机地址 -->
|
||||||
|
<a-form-item field="hostAddress" label="主机地址">
|
||||||
|
<a-input v-model="formModel.hostAddress" placeholder="请输入主机地址" allow-clear />
|
||||||
|
</a-form-item>
|
||||||
<!-- 类型 -->
|
<!-- 类型 -->
|
||||||
<a-form-item field="type" label="类型">
|
<a-form-item field="type" label="类型">
|
||||||
<a-select v-model="formModel.type"
|
<a-select v-model="formModel.type"
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>123</div>
|
<div class="layout-container">
|
||||||
|
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|||||||
@@ -7,31 +7,12 @@
|
|||||||
@submit="fetchTableData"
|
@submit="fetchTableData"
|
||||||
@reset="fetchTableData"
|
@reset="fetchTableData"
|
||||||
@keyup.enter="() => fetchTableData()">
|
@keyup.enter="() => fetchTableData()">
|
||||||
<!-- id -->
|
|
||||||
<a-form-item field="id" label="id">
|
|
||||||
<a-input-number v-model="formModel.id"
|
|
||||||
placeholder="请输入id"
|
|
||||||
allow-clear
|
|
||||||
hide-button />
|
|
||||||
</a-form-item>
|
|
||||||
<!-- 执行用户 -->
|
|
||||||
<a-form-item field="userId" label="执行用户">
|
|
||||||
<user-selector v-model="formModel.userId"
|
|
||||||
placeholder="请选择执行用户"
|
|
||||||
allow-clear />
|
|
||||||
</a-form-item>
|
|
||||||
<!-- 执行描述 -->
|
<!-- 执行描述 -->
|
||||||
<a-form-item field="description" label="执行描述">
|
<a-form-item field="description" label="执行描述">
|
||||||
<a-input v-model="formModel.description"
|
<a-input v-model="formModel.description"
|
||||||
placeholder="请输入执行描述"
|
placeholder="请输入执行描述"
|
||||||
allow-clear />
|
allow-clear />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<!-- 执行命令 -->
|
|
||||||
<a-form-item field="command" label="执行命令">
|
|
||||||
<a-input v-model="formModel.command"
|
|
||||||
placeholder="请输入执行命令"
|
|
||||||
allow-clear />
|
|
||||||
</a-form-item>
|
|
||||||
<!-- 执行状态 -->
|
<!-- 执行状态 -->
|
||||||
<a-form-item field="status" label="执行状态">
|
<a-form-item field="status" label="执行状态">
|
||||||
<a-select v-model="formModel.status"
|
<a-select v-model="formModel.status"
|
||||||
@@ -39,6 +20,25 @@
|
|||||||
placeholder="请选择执行状态"
|
placeholder="请选择执行状态"
|
||||||
allow-clear />
|
allow-clear />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<!-- 执行用户 -->
|
||||||
|
<a-form-item field="userId" label="执行用户">
|
||||||
|
<user-selector v-model="formModel.userId"
|
||||||
|
placeholder="请选择执行用户"
|
||||||
|
allow-clear />
|
||||||
|
</a-form-item>
|
||||||
|
<!-- 执行命令 -->
|
||||||
|
<a-form-item field="command" label="执行命令">
|
||||||
|
<a-input v-model="formModel.command"
|
||||||
|
placeholder="请输入执行命令"
|
||||||
|
allow-clear />
|
||||||
|
</a-form-item>
|
||||||
|
<!-- id -->
|
||||||
|
<a-form-item field="id" label="id">
|
||||||
|
<a-input-number v-model="formModel.id"
|
||||||
|
placeholder="请输入id"
|
||||||
|
allow-clear
|
||||||
|
hide-button />
|
||||||
|
</a-form-item>
|
||||||
<!-- 执行时间 -->
|
<!-- 执行时间 -->
|
||||||
<a-form-item field="startTimeRange" label="执行时间">
|
<a-form-item field="startTimeRange" label="执行时间">
|
||||||
<a-range-picker v-model="formModel.startTimeRange"
|
<a-range-picker v-model="formModel.startTimeRange"
|
||||||
@@ -204,6 +204,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import type { TableData } from '@arco-design/web-vue/es/table/interface';
|
||||||
import type { ExecLogQueryRequest, ExecLogQueryResponse } from '@/api/exec/exec-log';
|
import type { ExecLogQueryRequest, ExecLogQueryResponse } from '@/api/exec/exec-log';
|
||||||
import { reactive, ref, onMounted, onUnmounted } from 'vue';
|
import { reactive, ref, onMounted, onUnmounted } from 'vue';
|
||||||
import { batchDeleteExecLog, deleteExecLog, getExecHostLogList, getExecLogPage, getExecLogStatus } from '@/api/exec/exec-log';
|
import { batchDeleteExecLog, deleteExecLog, getExecHostLogList, getExecLogPage, getExecLogStatus } from '@/api/exec/exec-log';
|
||||||
@@ -312,7 +313,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 加载主机数据
|
// 加载主机数据
|
||||||
const loadHostExecData = async (key: number, record: ExecLogQueryResponse) => {
|
const loadHostExecData = async (key: number | string, record: TableData) => {
|
||||||
if (record.hosts) {
|
if (record.hosts) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,10 +44,11 @@
|
|||||||
</template>
|
</template>
|
||||||
</a-input-number>
|
</a-input-number>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<!-- 模板命令 -->
|
<!-- 执行命令 -->
|
||||||
<a-form-item field="command"
|
<a-form-item field="command"
|
||||||
label="模板命令"
|
label="执行命令"
|
||||||
:wrapper-col-props="{ span: 24 }">
|
:wrapper-col-props="{ span: 24 }"
|
||||||
|
:help="'使用 @{{ xxx }} 来替换参数, 输入_可以获取全部变量'">
|
||||||
<exec-editor v-model="formModel.command"
|
<exec-editor v-model="formModel.command"
|
||||||
containerClass="command-editor"
|
containerClass="command-editor"
|
||||||
theme="vs-dark"
|
theme="vs-dark"
|
||||||
@@ -72,7 +73,7 @@
|
|||||||
:field="item.name as string"
|
:field="item.name as string"
|
||||||
:label="item.name"
|
:label="item.name"
|
||||||
required>
|
required>
|
||||||
<a-input v-model="parameterFormModel[item.name]"
|
<a-input v-model="parameterFormModel[item.name as string]"
|
||||||
:placeholder="item.desc"
|
:placeholder="item.desc"
|
||||||
allow-clear />
|
allow-clear />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
@@ -101,7 +102,7 @@
|
|||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
import ExecEditor from '@/components/view/exec-editor/index.vue';
|
import ExecEditor from '@/components/view/exec-editor/index.vue';
|
||||||
import AuthorizedHostModal from '@/components/asset/host/authorized-host-modal/index.vue';
|
import AuthorizedHostModal from '@/components/asset/host/authorized-host-modal/index.vue';
|
||||||
import { execCommand } from '@/api/exec/exec';
|
import { batchExecCommand } from '@/api/exec/exec';
|
||||||
|
|
||||||
const { visible, setVisible } = useVisible();
|
const { visible, setVisible } = useVisible();
|
||||||
const { loading, setLoading } = useLoading();
|
const { loading, setLoading } = useLoading();
|
||||||
@@ -166,7 +167,8 @@
|
|||||||
if (error) {
|
if (error) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
await execCommand({
|
// 执行命令
|
||||||
|
await batchExecCommand({
|
||||||
...formModel.value,
|
...formModel.value,
|
||||||
parameter: JSON.stringify(parameterFormModel.value),
|
parameter: JSON.stringify(parameterFormModel.value),
|
||||||
parameterSchema: JSON.stringify(parameterSchema.value),
|
parameterSchema: JSON.stringify(parameterSchema.value),
|
||||||
|
|||||||
@@ -34,7 +34,8 @@
|
|||||||
<!-- 模板命令 -->
|
<!-- 模板命令 -->
|
||||||
<a-form-item field="command"
|
<a-form-item field="command"
|
||||||
label="模板命令"
|
label="模板命令"
|
||||||
:wrapper-col-props="{ span: 24 }">
|
:wrapper-col-props="{ span: 24 }"
|
||||||
|
:help="'使用 @{{ xxx }} 来替换参数, 输入_可以获取全部变量'">
|
||||||
<exec-editor v-model="formModel.command"
|
<exec-editor v-model="formModel.command"
|
||||||
containerClass="command-editor"
|
containerClass="command-editor"
|
||||||
theme="vs-dark"
|
theme="vs-dark"
|
||||||
|
|||||||
@@ -79,7 +79,8 @@
|
|||||||
<a-button v-permission="['asset:exec:exec-command']"
|
<a-button v-permission="['asset:exec:exec-command']"
|
||||||
type="text"
|
type="text"
|
||||||
size="mini"
|
size="mini"
|
||||||
@click="emits('openExec', record)">
|
title="ctrl + 鼠标左键新页面打开"
|
||||||
|
@click="openExec($event, record)">
|
||||||
执行
|
执行
|
||||||
</a-button>
|
</a-button>
|
||||||
<!-- 修改 -->
|
<!-- 修改 -->
|
||||||
@@ -120,7 +121,6 @@
|
|||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
import useLoading from '@/hooks/loading';
|
import useLoading from '@/hooks/loading';
|
||||||
import columns from '../types/table.columns';
|
import columns from '../types/table.columns';
|
||||||
import {} from '../types/const';
|
|
||||||
import { usePagination } from '@/types/table';
|
import { usePagination } from '@/types/table';
|
||||||
import useCopy from '@/hooks/copy';
|
import useCopy from '@/hooks/copy';
|
||||||
|
|
||||||
@@ -137,6 +137,15 @@
|
|||||||
command: undefined,
|
command: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 打开执行
|
||||||
|
const openExec = (e: any, record: ExecTemplateQueryResponse) => {
|
||||||
|
if (e.ctrlKey) {
|
||||||
|
// TODO 新页面打开
|
||||||
|
} else {
|
||||||
|
emits('openExec', record);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 删除当前行
|
// 删除当前行
|
||||||
const deleteRow = async ({ id }: {
|
const deleteRow = async ({ id }: {
|
||||||
id: number
|
id: number
|
||||||
|
|||||||
Reference in New Issue
Block a user