mirror of
https://gitee.com/dromara/Jpom.git
synced 2024-11-29 18:38:32 +08:00
fix DSL 项目控制台支持快捷编辑节点脚本(查看流程信息)
This commit is contained in:
parent
f07c052017
commit
017c00ee65
@ -15,6 +15,7 @@
|
||||
6. 【all】优化 授权目录判断逻辑
|
||||
7. 【agent】取消 插件端授权目录关闭包含判断(`jpom.whitelist.check-starts-with`)
|
||||
8. 【server】优化 触发器清理优化、删除用户主动删除关联触发器
|
||||
9. 【server】优化 DSL 项目控制台支持快捷编辑节点脚本(查看流程信息)
|
||||
|
||||
### ⚠️ 注意
|
||||
|
||||
|
@ -49,7 +49,7 @@ import org.dromara.jpom.model.data.DslYmlDto;
|
||||
import org.dromara.jpom.model.data.NodeProjectInfoModel;
|
||||
import org.dromara.jpom.model.system.NetstatModel;
|
||||
import org.dromara.jpom.plugin.PluginFactory;
|
||||
import org.dromara.jpom.script.DslScriptBuilder;
|
||||
import org.dromara.jpom.service.script.DslScriptServer;
|
||||
import org.dromara.jpom.socket.AgentFileTailWatcher;
|
||||
import org.dromara.jpom.socket.ConsoleCommandOp;
|
||||
import org.dromara.jpom.util.CommandUtil;
|
||||
@ -89,14 +89,17 @@ public abstract class AbstractProjectCommander implements ProjectCommander {
|
||||
protected final SystemCommander systemCommander;
|
||||
protected final ProjectConfig projectConfig;
|
||||
protected final ProjectLogConfig projectLogConfig;
|
||||
protected final DslScriptServer dslScriptServer;
|
||||
|
||||
public AbstractProjectCommander(Charset fileCharset,
|
||||
SystemCommander systemCommander,
|
||||
ProjectConfig projectConfig) {
|
||||
ProjectConfig projectConfig,
|
||||
DslScriptServer dslScriptServer) {
|
||||
this.fileCharset = fileCharset;
|
||||
this.systemCommander = systemCommander;
|
||||
this.projectConfig = projectConfig;
|
||||
this.projectLogConfig = projectConfig.getLog();
|
||||
this.dslScriptServer = dslScriptServer;
|
||||
}
|
||||
|
||||
|
||||
@ -108,7 +111,7 @@ public abstract class AbstractProjectCommander implements ProjectCommander {
|
||||
* @param nodeProjectInfoModel 项目
|
||||
* @return null 是条件不足
|
||||
*/
|
||||
public abstract String buildJavaCommand(NodeProjectInfoModel nodeProjectInfoModel);
|
||||
public abstract String buildRunCommand(NodeProjectInfoModel nodeProjectInfoModel);
|
||||
|
||||
protected String getRunJavaPath(NodeProjectInfoModel nodeProjectInfoModel, boolean w) {
|
||||
// if (StrUtil.isEmpty(nodeProjectInfoModel.getJdkId())) {
|
||||
@ -153,7 +156,7 @@ public abstract class AbstractProjectCommander implements ProjectCommander {
|
||||
this.runDsl(nodeProjectInfoModel, ConsoleCommandOp.start.name(), (baseProcess, action) -> {
|
||||
String log = nodeProjectInfoModel.getAbsoluteLog();
|
||||
try {
|
||||
DslScriptBuilder.run(baseProcess, nodeProjectInfoModel, action, log, sync);
|
||||
dslScriptServer.run(baseProcess, nodeProjectInfoModel, action, log, sync);
|
||||
} catch (Exception e) {
|
||||
throw Lombok.sneakyThrow(e);
|
||||
}
|
||||
@ -161,7 +164,7 @@ public abstract class AbstractProjectCommander implements ProjectCommander {
|
||||
});
|
||||
|
||||
} else {
|
||||
String command = this.buildJavaCommand(nodeProjectInfoModel);
|
||||
String command = this.buildRunCommand(nodeProjectInfoModel);
|
||||
if (command == null) {
|
||||
return CommandOpResult.of(false, "没有需要执行的命令");
|
||||
}
|
||||
@ -172,7 +175,7 @@ public abstract class AbstractProjectCommander implements ProjectCommander {
|
||||
if (SystemUtil.getOsInfo().isWindows()) {
|
||||
CommandUtil.execSystemCommand(command, file);
|
||||
} else {
|
||||
CommandUtil.asyncExeLocalCommand(file, command);
|
||||
CommandUtil.asyncExeLocalCommand(command, file);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("执行命令失败", e);
|
||||
@ -232,7 +235,7 @@ public abstract class AbstractProjectCommander implements ProjectCommander {
|
||||
this.runDsl(nodeProjectInfoModel, ConsoleCommandOp.stop.name(), (process, action) -> {
|
||||
String log = nodeProjectInfoModel.getAbsoluteLog();
|
||||
try {
|
||||
DslScriptBuilder.run(process, nodeProjectInfoModel, action, log, sync);
|
||||
dslScriptServer.run(process, nodeProjectInfoModel, action, log, sync);
|
||||
} catch (Exception e) {
|
||||
throw Lombok.sneakyThrow(e);
|
||||
}
|
||||
@ -305,7 +308,7 @@ public abstract class AbstractProjectCommander implements ProjectCommander {
|
||||
if (ArrayUtil.contains(other, "fileChange")) {
|
||||
RunMode runMode = nodeProjectInfoModel.getRunMode();
|
||||
if (runMode == RunMode.Dsl) {
|
||||
DslYmlDto dslYmlDto = nodeProjectInfoModel.dslConfig();
|
||||
DslYmlDto dslYmlDto = nodeProjectInfoModel.mustDslConfig();
|
||||
if (dslYmlDto.hasRunProcess(ConsoleCommandOp.reload.name())) {
|
||||
DslYmlDto.Run run = dslYmlDto.getRun();
|
||||
Boolean fileChangeReload = run.getFileChangeReload();
|
||||
@ -365,13 +368,14 @@ public abstract class AbstractProjectCommander implements ProjectCommander {
|
||||
}
|
||||
this.asyncWebHooks(nodeProjectInfoModel, "beforeRestart");
|
||||
if (runMode == RunMode.Dsl) {
|
||||
DslYmlDto.BaseProcess dslProcess = nodeProjectInfoModel.tryDslProcess("restart");
|
||||
DslYmlDto.BaseProcess dslProcess = nodeProjectInfoModel.tryDslProcess(ConsoleCommandOp.restart.name());
|
||||
if (dslProcess != null) {
|
||||
// 如果存在自定义 restart 流程
|
||||
//
|
||||
this.runDsl(nodeProjectInfoModel, ConsoleCommandOp.restart.name(), (process, action) -> {
|
||||
String log = nodeProjectInfoModel.getAbsoluteLog();
|
||||
try {
|
||||
DslScriptBuilder.run(process, nodeProjectInfoModel, action, log, false);
|
||||
dslScriptServer.run(process, nodeProjectInfoModel, action, log, false);
|
||||
} catch (Exception e) {
|
||||
throw Lombok.sneakyThrow(e);
|
||||
}
|
||||
@ -475,8 +479,7 @@ public abstract class AbstractProjectCommander implements ProjectCommander {
|
||||
RunMode runMode = nodeProjectInfoModel.getRunMode();
|
||||
boolean autoBackToFile = projectLogConfig.isAutoBackupToFile();
|
||||
if (runMode == RunMode.Dsl) {
|
||||
DslYmlDto dslYmlDto = nodeProjectInfoModel.dslConfig();
|
||||
return Optional.ofNullable(dslYmlDto)
|
||||
return Optional.ofNullable(nodeProjectInfoModel.dslConfig())
|
||||
.map(DslYmlDto::getConfig)
|
||||
.map(DslYmlDto.Config::getAutoBackToFile)
|
||||
.orElse(autoBackToFile);
|
||||
@ -532,7 +535,7 @@ public abstract class AbstractProjectCommander implements ProjectCommander {
|
||||
List<String> status = this.runDsl(nodeProjectInfoModel, ConsoleCommandOp.status.name(), (baseProcess, action) -> {
|
||||
// 提前判断脚本 id,避免填写错误在删除项目检测状态时候异常
|
||||
try {
|
||||
Tuple tuple = DslScriptBuilder.syncRun(baseProcess, nodeProjectInfoModel, action);
|
||||
Tuple tuple = dslScriptServer.syncRun(baseProcess, nodeProjectInfoModel, action);
|
||||
return tuple.get(1);
|
||||
} catch (IllegalArgument2Exception argument2Exception) {
|
||||
log.warn("执行 DSL 脚本异常:{}", argument2Exception.getMessage());
|
||||
@ -576,9 +579,10 @@ public abstract class AbstractProjectCommander implements ProjectCommander {
|
||||
return this.runDsl(nodeProjectInfoModel, ConsoleCommandOp.reload.name(), (baseProcess, action) -> {
|
||||
// 提前判断脚本 id,避免填写错误在删除项目检测状态时候异常
|
||||
try {
|
||||
Tuple tuple = DslScriptBuilder.syncRun(baseProcess, nodeProjectInfoModel, action);
|
||||
Tuple tuple = dslScriptServer.syncRun(baseProcess, nodeProjectInfoModel, action);
|
||||
int code = tuple.get(0);
|
||||
List<String> list = tuple.get(1);
|
||||
// 如果退出码为 0 认为执行成功
|
||||
return CommandOpResult.of(code == 0, list);
|
||||
} catch (IllegalArgument2Exception argument2Exception) {
|
||||
log.warn("执行 DSL 脚本异常:{}", argument2Exception.getMessage());
|
||||
@ -595,12 +599,23 @@ public abstract class AbstractProjectCommander implements ProjectCommander {
|
||||
*/
|
||||
protected String status(String tag) {
|
||||
String jpsStatus = this.getJpsStatus(tag);
|
||||
if (StrUtil.equals(AbstractProjectCommander.STOP_TAG, jpsStatus) && SystemUtil.getOsInfo().isLinux()) {
|
||||
return getLinuxPsStatus(tag);
|
||||
if (StrUtil.equals(AbstractProjectCommander.STOP_TAG, jpsStatus)) {
|
||||
// 通过系统命令查询
|
||||
return this.bySystemPs(tag);
|
||||
}
|
||||
return jpsStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过系统命令查询进程是否存在
|
||||
*
|
||||
* @param tag 进程标识
|
||||
* @return 是否存在
|
||||
*/
|
||||
protected String bySystemPs(String tag) {
|
||||
return AbstractProjectCommander.STOP_TAG;
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试jps 中查看进程id
|
||||
*
|
||||
@ -615,26 +630,6 @@ public abstract class AbstractProjectCommander implements ProjectCommander {
|
||||
return StrUtil.format("{}:{}", AbstractProjectCommander.RUNNING_TAG, pid);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 尝试ps -ef | grep 中查看进程id
|
||||
*
|
||||
* @param tag 进程标识
|
||||
* @return 运行标识
|
||||
*/
|
||||
private String getLinuxPsStatus(String tag) {
|
||||
String execSystemCommand = CommandUtil.execSystemCommand("ps -ef | grep " + tag);
|
||||
log.debug("getLinuxPsStatus {} {}", tag, execSystemCommand);
|
||||
List<String> list = StrSplitter.splitTrim(execSystemCommand, StrUtil.LF, true);
|
||||
for (String item : list) {
|
||||
if (JvmUtil.checkCommandLineIsJpom(item, tag)) {
|
||||
String[] split = StrUtil.splitToArray(item, StrUtil.SPACE);
|
||||
return StrUtil.format("{}:{}", AbstractProjectCommander.RUNNING_TAG, split[1]);
|
||||
}
|
||||
}
|
||||
return AbstractProjectCommander.STOP_TAG;
|
||||
}
|
||||
|
||||
//---------------------------------------------------- 基本操作----end
|
||||
|
||||
/**
|
||||
|
@ -23,11 +23,13 @@
|
||||
package org.dromara.jpom.common.commander;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.text.StrSplitter;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.Lombok;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.jpom.configuration.ProjectConfig;
|
||||
import org.dromara.jpom.configuration.ProjectLogConfig;
|
||||
import org.dromara.jpom.model.data.NodeProjectInfoModel;
|
||||
import org.dromara.jpom.service.script.DslScriptServer;
|
||||
import org.dromara.jpom.util.CommandUtil;
|
||||
import org.dromara.jpom.util.JvmUtil;
|
||||
|
||||
@ -43,16 +45,18 @@ import java.util.Optional;
|
||||
* @author bwcx_jzy
|
||||
* @since 2021/12/17
|
||||
*/
|
||||
@Slf4j
|
||||
public abstract class BaseUnixProjectCommander extends AbstractProjectCommander {
|
||||
|
||||
public BaseUnixProjectCommander(Charset fileCharset,
|
||||
SystemCommander systemCommander,
|
||||
ProjectConfig projectConfig) {
|
||||
super(fileCharset, systemCommander, projectConfig);
|
||||
ProjectConfig projectConfig,
|
||||
DslScriptServer dslScriptServer) {
|
||||
super(fileCharset, systemCommander, projectConfig, dslScriptServer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String buildJavaCommand(NodeProjectInfoModel nodeProjectInfoModel) {
|
||||
public String buildRunCommand(NodeProjectInfoModel nodeProjectInfoModel) {
|
||||
String path = NodeProjectInfoModel.getClassPathLib(nodeProjectInfoModel);
|
||||
if (StrUtil.isBlank(path)) {
|
||||
return null;
|
||||
@ -82,7 +86,7 @@ public abstract class BaseUnixProjectCommander extends AbstractProjectCommander
|
||||
result.add("Kill not completed, test kill -9");
|
||||
String cmd = String.format("kill -9 %s", pid);
|
||||
try {
|
||||
CommandUtil.asyncExeLocalCommand(file, cmd);
|
||||
CommandUtil.asyncExeLocalCommand(cmd, file);
|
||||
} catch (Exception e) {
|
||||
throw Lombok.sneakyThrow(e);
|
||||
}
|
||||
@ -97,4 +101,24 @@ public abstract class BaseUnixProjectCommander extends AbstractProjectCommander
|
||||
return CommandOpResult.of(success, status(tag)).appendMsg(result);
|
||||
// return status(tag) + StrUtil.SPACE + kill;
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试ps -ef | grep 中查看进程id
|
||||
*
|
||||
* @param tag 进程标识
|
||||
* @return 运行标识
|
||||
*/
|
||||
@Override
|
||||
protected String bySystemPs(String tag) {
|
||||
String execSystemCommand = CommandUtil.execSystemCommand("ps -ef | grep " + tag);
|
||||
log.debug("getPsStatus {} {}", tag, execSystemCommand);
|
||||
List<String> list = StrSplitter.splitTrim(execSystemCommand, StrUtil.LF, true);
|
||||
for (String item : list) {
|
||||
if (JvmUtil.checkCommandLineIsJpom(item, tag)) {
|
||||
String[] split = StrUtil.splitToArray(item, StrUtil.SPACE);
|
||||
return StrUtil.format("{}:{}", AbstractProjectCommander.RUNNING_TAG, split[1]);
|
||||
}
|
||||
}
|
||||
return AbstractProjectCommander.STOP_TAG;
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ public interface ProjectCommander {
|
||||
* @param nodeProjectInfoModel 项目
|
||||
* @return null 是条件不足
|
||||
*/
|
||||
String buildJavaCommand(NodeProjectInfoModel nodeProjectInfoModel);
|
||||
String buildRunCommand(NodeProjectInfoModel nodeProjectInfoModel);
|
||||
|
||||
/**
|
||||
* 执行 webhooks 通知
|
||||
|
@ -25,11 +25,13 @@ package org.dromara.jpom.common.commander.impl;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.text.StrSplitter;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.jpom.common.commander.BaseUnixProjectCommander;
|
||||
import org.dromara.jpom.common.commander.Commander;
|
||||
import org.dromara.jpom.common.commander.SystemCommander;
|
||||
import org.dromara.jpom.model.system.NetstatModel;
|
||||
import org.dromara.jpom.configuration.AgentConfig;
|
||||
import org.dromara.jpom.model.system.NetstatModel;
|
||||
import org.dromara.jpom.service.script.DslScriptServer;
|
||||
import org.dromara.jpom.util.CommandUtil;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
@ -47,11 +49,13 @@ import java.util.stream.Collectors;
|
||||
@Conditional(Commander.Linux.class)
|
||||
@Service
|
||||
@Primary
|
||||
@Slf4j
|
||||
public class LinuxProjectCommander extends BaseUnixProjectCommander {
|
||||
|
||||
public LinuxProjectCommander(AgentConfig agentConfig,
|
||||
SystemCommander systemCommander) {
|
||||
super(agentConfig.getProject().getLog().getFileCharset(), systemCommander, agentConfig.getProject());
|
||||
SystemCommander systemCommander,
|
||||
DslScriptServer dslScriptServer) {
|
||||
super(agentConfig.getProject().getLog().getFileCharset(), systemCommander, agentConfig.getProject(), dslScriptServer);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -30,6 +30,7 @@ import org.dromara.jpom.common.commander.Commander;
|
||||
import org.dromara.jpom.common.commander.SystemCommander;
|
||||
import org.dromara.jpom.configuration.AgentConfig;
|
||||
import org.dromara.jpom.model.system.NetstatModel;
|
||||
import org.dromara.jpom.service.script.DslScriptServer;
|
||||
import org.dromara.jpom.util.CommandUtil;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -50,8 +51,9 @@ import java.util.stream.Collectors;
|
||||
public class MacOsProjectCommander extends BaseUnixProjectCommander {
|
||||
|
||||
public MacOsProjectCommander(AgentConfig agentConfig,
|
||||
SystemCommander systemCommander) {
|
||||
super(agentConfig.getProject().getLog().getFileCharset(), systemCommander, agentConfig.getProject());
|
||||
SystemCommander systemCommander,
|
||||
DslScriptServer dslScriptServer) {
|
||||
super(agentConfig.getProject().getLog().getFileCharset(), systemCommander, agentConfig.getProject(), dslScriptServer);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -71,26 +73,29 @@ public class MacOsProjectCommander extends BaseUnixProjectCommander {
|
||||
if (CollUtil.isEmpty(netList)) {
|
||||
return null;
|
||||
}
|
||||
return netList.stream().map(str -> {
|
||||
List<String> list = StrSplitter.splitTrim(str, " ", true);
|
||||
if (list.size() < 10) {
|
||||
return null;
|
||||
}
|
||||
NetstatModel netstatModel = new NetstatModel();
|
||||
netstatModel.setProtocol(list.get(7));
|
||||
//netstatModel.setReceive(list.get(1));
|
||||
//netstatModel.setSend(list.get(2));
|
||||
netstatModel.setLocal(list.get(8));
|
||||
netstatModel.setForeign(list.get(4));
|
||||
if ("tcp".equalsIgnoreCase(netstatModel.getProtocol())) {
|
||||
netstatModel.setStatus(CollUtil.get(list, 9));
|
||||
netstatModel.setName(CollUtil.get(list, 0));
|
||||
} else {
|
||||
netstatModel.setStatus(StrUtil.DASHED);
|
||||
netstatModel.setName(CollUtil.get(list, 5));
|
||||
}
|
||||
return netList.stream()
|
||||
.map(str -> {
|
||||
List<String> list = StrSplitter.splitTrim(str, " ", true);
|
||||
if (list.size() < 10) {
|
||||
return null;
|
||||
}
|
||||
NetstatModel netstatModel = new NetstatModel();
|
||||
netstatModel.setProtocol(list.get(7));
|
||||
//netstatModel.setReceive(list.get(1));
|
||||
//netstatModel.setSend(list.get(2));
|
||||
netstatModel.setLocal(list.get(8));
|
||||
netstatModel.setForeign(list.get(4));
|
||||
if ("tcp".equalsIgnoreCase(netstatModel.getProtocol())) {
|
||||
netstatModel.setStatus(CollUtil.get(list, 9));
|
||||
netstatModel.setName(CollUtil.get(list, 0));
|
||||
} else {
|
||||
netstatModel.setStatus(StrUtil.DASHED);
|
||||
netstatModel.setName(CollUtil.get(list, 5));
|
||||
}
|
||||
|
||||
return netstatModel;
|
||||
}).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
return netstatModel;
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ import org.dromara.jpom.common.commander.SystemCommander;
|
||||
import org.dromara.jpom.model.data.NodeProjectInfoModel;
|
||||
import org.dromara.jpom.model.system.NetstatModel;
|
||||
import org.dromara.jpom.configuration.AgentConfig;
|
||||
import org.dromara.jpom.service.script.DslScriptServer;
|
||||
import org.dromara.jpom.util.CommandUtil;
|
||||
import org.dromara.jpom.util.JvmUtil;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
@ -51,12 +52,13 @@ import java.util.Optional;
|
||||
public class WindowsProjectCommander extends AbstractProjectCommander {
|
||||
|
||||
public WindowsProjectCommander(AgentConfig agentConfig,
|
||||
SystemCommander systemCommander) {
|
||||
super(agentConfig.getProject().getLog().getFileCharset(), systemCommander, agentConfig.getProject());
|
||||
SystemCommander systemCommander,
|
||||
DslScriptServer dslScriptServer) {
|
||||
super(agentConfig.getProject().getLog().getFileCharset(), systemCommander, agentConfig.getProject(), dslScriptServer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String buildJavaCommand(NodeProjectInfoModel nodeProjectInfoModel) {
|
||||
public String buildRunCommand(NodeProjectInfoModel nodeProjectInfoModel) {
|
||||
String classPath = NodeProjectInfoModel.getClassPathLib(nodeProjectInfoModel);
|
||||
if (StrUtil.isBlank(classPath)) {
|
||||
return null;
|
||||
@ -122,4 +124,7 @@ public class WindowsProjectCommander extends AbstractProjectCommander {
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
// tasklist | findstr /s /i "java"
|
||||
// wmic process where caption="javaw.exe" get processid,caption,commandline /value
|
||||
}
|
||||
|
@ -22,21 +22,26 @@
|
||||
*/
|
||||
package org.dromara.jpom.controller.manage;
|
||||
|
||||
import cn.hutool.core.lang.Tuple;
|
||||
import cn.keepbx.jpom.IJsonMessage;
|
||||
import cn.keepbx.jpom.model.JsonMessage;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.jpom.common.BaseAgentController;
|
||||
import org.dromara.jpom.common.commander.ProjectCommander;
|
||||
import org.dromara.jpom.model.RunMode;
|
||||
import org.dromara.jpom.model.data.DslYmlDto;
|
||||
import org.dromara.jpom.model.data.NodeProjectInfoModel;
|
||||
import org.dromara.jpom.service.script.DslScriptServer;
|
||||
import org.dromara.jpom.socket.ConsoleCommandOp;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 管理的信息获取接口
|
||||
@ -50,9 +55,12 @@ import java.util.List;
|
||||
public class ProjectListController extends BaseAgentController {
|
||||
|
||||
private final ProjectCommander projectCommander;
|
||||
private final DslScriptServer dslScriptServer;
|
||||
|
||||
public ProjectListController(ProjectCommander projectCommander) {
|
||||
public ProjectListController(ProjectCommander projectCommander,
|
||||
DslScriptServer dslScriptServer) {
|
||||
this.projectCommander = projectCommander;
|
||||
this.dslScriptServer = dslScriptServer;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -69,13 +77,24 @@ public class ProjectListController extends BaseAgentController {
|
||||
RunMode runMode = nodeProjectInfoModel.getRunMode();
|
||||
if (runMode != RunMode.Dsl && runMode != RunMode.File) {
|
||||
// 返回实际执行的命令
|
||||
String command = projectCommander.buildJavaCommand(nodeProjectInfoModel);
|
||||
String command = projectCommander.buildRunCommand(nodeProjectInfoModel);
|
||||
nodeProjectInfoModel.setRunCommand(command);
|
||||
}
|
||||
if (runMode == RunMode.Dsl) {
|
||||
DslYmlDto dslYmlDto = nodeProjectInfoModel.dslConfig();
|
||||
DslYmlDto dslYmlDto = nodeProjectInfoModel.mustDslConfig();
|
||||
boolean reload = dslYmlDto.hasRunProcess(ConsoleCommandOp.reload.name());
|
||||
nodeProjectInfoModel.setCanReload(reload);
|
||||
// 查询 dsl 流程信息
|
||||
List<JSONObject> list = Arrays.stream(ConsoleCommandOp.values())
|
||||
.filter(ConsoleCommandOp::isCanOpt)
|
||||
.map(consoleCommandOp -> {
|
||||
Tuple tuple = dslScriptServer.resolveProcessScript(nodeProjectInfoModel, dslYmlDto, consoleCommandOp);
|
||||
JSONObject jsonObject = tuple.get(0);
|
||||
jsonObject.put("process", consoleCommandOp);
|
||||
return jsonObject;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
nodeProjectInfoModel.setDslProcessInfo(list);
|
||||
}
|
||||
}
|
||||
return JsonMessage.success("", nodeProjectInfoModel);
|
||||
|
@ -20,7 +20,7 @@
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package org.dromara.jpom.controller.manage.log;
|
||||
package org.dromara.jpom.controller.manage;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.extra.servlet.ServletUtil;
|
||||
@ -50,11 +50,11 @@ import java.util.List;
|
||||
@RestController
|
||||
@RequestMapping(value = "manage/log")
|
||||
@Slf4j
|
||||
public class LogBackController extends BaseAgentController {
|
||||
public class ProjectLogBackController extends BaseAgentController {
|
||||
|
||||
private final ProjectCommander projectCommander;
|
||||
|
||||
public LogBackController(ProjectCommander projectCommander) {
|
||||
public ProjectLogBackController(ProjectCommander projectCommander) {
|
||||
this.projectCommander = projectCommander;
|
||||
}
|
||||
|
@ -23,12 +23,10 @@
|
||||
package org.dromara.jpom.model.data;
|
||||
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.setting.yaml.YamlUtil;
|
||||
import cn.keepbx.jpom.model.BaseJsonModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
@ -63,14 +61,6 @@ public class DslYmlDto extends BaseJsonModel {
|
||||
*/
|
||||
private Config config;
|
||||
|
||||
public DslYmlDto.BaseProcess runProcess(String opt) {
|
||||
DslYmlDto.Run run = this.getRun();
|
||||
Assert.notNull(run, "yml 未配置 运行管理");
|
||||
DslYmlDto.BaseProcess baseProcess = (DslYmlDto.BaseProcess) ReflectUtil.getFieldValue(run, opt);
|
||||
Assert.notNull(baseProcess, "未找到对应的类型或者未配置 " + opt);
|
||||
return baseProcess;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否包含指定流程
|
||||
*
|
||||
@ -116,6 +106,8 @@ public class DslYmlDto extends BaseJsonModel {
|
||||
|
||||
/**
|
||||
* 重新加载
|
||||
*
|
||||
* @see org.dromara.jpom.socket.ConsoleCommandOp
|
||||
*/
|
||||
public static class Reload extends BaseProcess {
|
||||
|
||||
@ -123,6 +115,8 @@ public class DslYmlDto extends BaseJsonModel {
|
||||
|
||||
/**
|
||||
* 启动流程
|
||||
*
|
||||
* @see org.dromara.jpom.socket.ConsoleCommandOp
|
||||
*/
|
||||
public static class Start extends BaseProcess {
|
||||
|
||||
@ -130,6 +124,8 @@ public class DslYmlDto extends BaseJsonModel {
|
||||
|
||||
/**
|
||||
* 获取状态流程
|
||||
*
|
||||
* @see org.dromara.jpom.socket.ConsoleCommandOp
|
||||
*/
|
||||
public static class Status extends BaseProcess {
|
||||
|
||||
@ -137,6 +133,8 @@ public class DslYmlDto extends BaseJsonModel {
|
||||
|
||||
/**
|
||||
* 停止流程
|
||||
*
|
||||
* @see org.dromara.jpom.socket.ConsoleCommandOp
|
||||
*/
|
||||
public static class Stop extends BaseProcess {
|
||||
|
||||
@ -144,6 +142,8 @@ public class DslYmlDto extends BaseJsonModel {
|
||||
|
||||
/**
|
||||
* 重启流程
|
||||
*
|
||||
* @see org.dromara.jpom.socket.ConsoleCommandOp
|
||||
*/
|
||||
public static class Restart extends BaseProcess {
|
||||
|
||||
@ -164,15 +164,6 @@ public class DslYmlDto extends BaseJsonModel {
|
||||
* 执行脚本的环境变量
|
||||
*/
|
||||
private Map<String, String> scriptEnv;
|
||||
|
||||
/**
|
||||
* 通过 脚本模版运行
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
public boolean runByScript() {
|
||||
return StrUtil.isNotEmpty(this.getScriptId());
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
|
@ -27,6 +27,7 @@ import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.jpom.model.RunMode;
|
||||
@ -108,10 +109,16 @@ public class NodeProjectInfoModel extends BaseWorkspaceModel {
|
||||
* dsl 环境变量
|
||||
*/
|
||||
private String dslEnv;
|
||||
// ---------------- 中转字段 start
|
||||
/**
|
||||
* 是否可以重新加载
|
||||
*/
|
||||
private Boolean canReload;
|
||||
/**
|
||||
* DSL 流程信息统计
|
||||
*/
|
||||
private List<JSONObject> dslProcessInfo;
|
||||
// ---------------- 中转字段 end
|
||||
|
||||
public String getJavaExtDirsCp() {
|
||||
return StrUtil.emptyToDefault(javaExtDirsCp, StrUtil.EMPTY);
|
||||
@ -263,6 +270,11 @@ public class NodeProjectInfoModel extends BaseWorkspaceModel {
|
||||
return StrUtil.emptyToDefault(token, StrUtil.EMPTY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前 dsl 配置
|
||||
*
|
||||
* @return DslYmlDto
|
||||
*/
|
||||
public DslYmlDto dslConfig() {
|
||||
String dslContent = this.getDslContent();
|
||||
if (StrUtil.isEmpty(dslContent)) {
|
||||
@ -271,6 +283,17 @@ public class NodeProjectInfoModel extends BaseWorkspaceModel {
|
||||
return DslYmlDto.build(dslContent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 必须存在 dsl 配置
|
||||
*
|
||||
* @return DslYmlDto
|
||||
*/
|
||||
public DslYmlDto mustDslConfig() {
|
||||
DslYmlDto dslYmlDto = this.dslConfig();
|
||||
Assert.notNull(dslYmlDto, "未配置 dsl 信息(项目信息错误)");
|
||||
return dslYmlDto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 dsl 流程信息
|
||||
*
|
||||
@ -279,6 +302,16 @@ public class NodeProjectInfoModel extends BaseWorkspaceModel {
|
||||
*/
|
||||
public DslYmlDto.BaseProcess tryDslProcess(String opt) {
|
||||
DslYmlDto build = dslConfig();
|
||||
return tryDslProcess(build, opt);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 dsl 流程信息
|
||||
*
|
||||
* @param opt 操作
|
||||
* @return 结果
|
||||
*/
|
||||
public static DslYmlDto.BaseProcess tryDslProcess(DslYmlDto build, String opt) {
|
||||
return Optional.ofNullable(build)
|
||||
.map(DslYmlDto::getRun)
|
||||
.map(run -> (DslYmlDto.BaseProcess) ReflectUtil.getFieldValue(run, opt))
|
||||
@ -292,8 +325,8 @@ public class NodeProjectInfoModel extends BaseWorkspaceModel {
|
||||
* @return 结果
|
||||
*/
|
||||
public DslYmlDto.BaseProcess getDslProcess(String opt) {
|
||||
DslYmlDto build = dslConfig();
|
||||
Assert.notNull(build, "yml 还未配置");
|
||||
return build.runProcess(opt);
|
||||
DslYmlDto.BaseProcess baseProcess = this.tryDslProcess(opt);
|
||||
Assert.notNull(baseProcess, "DSL 未配置运行管理或者未配置 " + opt + " 流程");
|
||||
return baseProcess;
|
||||
}
|
||||
}
|
||||
|
@ -28,38 +28,18 @@ import cn.hutool.core.date.DateTime;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.io.LineHandler;
|
||||
import cn.hutool.core.lang.Opt;
|
||||
import cn.hutool.core.lang.Tuple;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.net.url.UrlQuery;
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.jpom.JpomApplication;
|
||||
import org.dromara.jpom.common.Const;
|
||||
import org.dromara.jpom.common.IllegalArgument2Exception;
|
||||
import org.dromara.jpom.configuration.ProjectLogConfig;
|
||||
import org.dromara.jpom.model.EnvironmentMapBuilder;
|
||||
import org.dromara.jpom.model.data.DslYmlDto;
|
||||
import org.dromara.jpom.model.data.NodeProjectInfoModel;
|
||||
import org.dromara.jpom.model.data.NodeScriptModel;
|
||||
import org.dromara.jpom.service.script.NodeScriptServer;
|
||||
import org.dromara.jpom.service.system.AgentWorkspaceEnvVarService;
|
||||
import org.dromara.jpom.configuration.AgentConfig;
|
||||
import org.dromara.jpom.system.ExtConfigBean;
|
||||
import org.dromara.jpom.util.CommandUtil;
|
||||
import org.dromara.jpom.util.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* dsl 执行脚本
|
||||
@ -78,11 +58,11 @@ public class DslScriptBuilder extends BaseRunScript implements Runnable {
|
||||
private boolean autoDelete;
|
||||
private EnvironmentMapBuilder environmentMapBuilder;
|
||||
|
||||
private DslScriptBuilder(String action,
|
||||
EnvironmentMapBuilder environmentMapBuilder,
|
||||
String args,
|
||||
String log,
|
||||
Charset charset) {
|
||||
public DslScriptBuilder(String action,
|
||||
EnvironmentMapBuilder environmentMapBuilder,
|
||||
String args,
|
||||
String log,
|
||||
Charset charset) {
|
||||
super(FileUtil.file(log), charset);
|
||||
this.action = action;
|
||||
this.environmentMapBuilder = environmentMapBuilder;
|
||||
@ -191,102 +171,5 @@ public class DslScriptBuilder extends BaseRunScript implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步执行
|
||||
*
|
||||
* @param scriptProcess 脚本流程
|
||||
* @param log 日志
|
||||
*/
|
||||
public static void run(DslYmlDto.BaseProcess scriptProcess, NodeProjectInfoModel nodeProjectInfoModel, String action, String log, boolean sync) throws Exception {
|
||||
DslScriptBuilder builder = DslScriptBuilder.create(scriptProcess, nodeProjectInfoModel, action, log);
|
||||
Future<?> execute = ThreadUtil.execAsync(builder);
|
||||
if (sync) {
|
||||
execute.get();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步执行
|
||||
*
|
||||
* @param scriptProcess 脚本流程
|
||||
*/
|
||||
public static Tuple syncRun(DslYmlDto.BaseProcess scriptProcess, NodeProjectInfoModel nodeProjectInfoModel, String action) {
|
||||
try (DslScriptBuilder builder = DslScriptBuilder.create(scriptProcess, nodeProjectInfoModel, action, null)) {
|
||||
return builder.syncExecute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建 DSL 执行器
|
||||
*
|
||||
* @param scriptProcess 脚本流程
|
||||
* @param nodeProjectInfoModel 项目
|
||||
* @param log 日志路径
|
||||
* @param action 具体操作
|
||||
*/
|
||||
private static DslScriptBuilder create(DslYmlDto.BaseProcess scriptProcess, NodeProjectInfoModel nodeProjectInfoModel, String action, String log) {
|
||||
NodeScriptServer nodeScriptServer = SpringUtil.getBean(NodeScriptServer.class);
|
||||
AgentConfig agentConfig = SpringUtil.getBean(AgentConfig.class);
|
||||
ProjectLogConfig logConfig = agentConfig.getProject().getLog();
|
||||
String scriptId = scriptProcess.getScriptId();
|
||||
cn.hutool.core.lang.Assert.notBlank(scriptId, () -> new IllegalArgument2Exception("请填写脚本模板id"));
|
||||
|
||||
NodeScriptModel item = nodeScriptServer.getItem(scriptId);
|
||||
EnvironmentMapBuilder environment = DslScriptBuilder.environment(nodeProjectInfoModel, scriptProcess);
|
||||
File scriptFile;
|
||||
boolean autoDelete = false;
|
||||
if (item == null) {
|
||||
scriptFile = FileUtil.file(nodeProjectInfoModel.allLib(), scriptId);
|
||||
cn.hutool.core.lang.Assert.isTrue(FileUtil.isFile(scriptFile), () -> new IllegalArgument2Exception("脚本模版不存在:" + scriptProcess.getScriptId()));
|
||||
} else {
|
||||
scriptFile = DslScriptBuilder.initScriptFile(item);
|
||||
// 系统生成的脚本需要自动删除
|
||||
autoDelete = true;
|
||||
}
|
||||
DslScriptBuilder builder = new DslScriptBuilder(action, environment, scriptProcess.getScriptArgs(), log, logConfig.getFileCharset());
|
||||
builder.setScriptFile(scriptFile);
|
||||
builder.setAutoDelete(autoDelete);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建脚本文件
|
||||
*
|
||||
* @param scriptModel 脚本对象
|
||||
* @return file
|
||||
*/
|
||||
private static File initScriptFile(NodeScriptModel scriptModel) {
|
||||
String dataPath = JpomApplication.getInstance().getDataPath();
|
||||
File scriptFile = FileUtil.file(dataPath, Const.SCRIPT_RUN_CACHE_DIRECTORY, StrUtil.format("{}.{}", IdUtil.fastSimpleUUID(), CommandUtil.SUFFIX));
|
||||
// 替换内容
|
||||
String context = scriptModel.getContext();
|
||||
FileUtils.writeScript(context, scriptFile, ExtConfigBean.getConsoleLogCharset());
|
||||
return scriptFile;
|
||||
}
|
||||
|
||||
private static EnvironmentMapBuilder environment(NodeProjectInfoModel nodeProjectInfoModel, DslYmlDto.BaseProcess scriptProcess) {
|
||||
//
|
||||
AgentWorkspaceEnvVarService workspaceService = SpringUtil.getBean(AgentWorkspaceEnvVarService.class);
|
||||
EnvironmentMapBuilder environmentMapBuilder = workspaceService.getEnv(nodeProjectInfoModel.getWorkspaceId());
|
||||
// 项目配置的环境变量
|
||||
String dslEnv = nodeProjectInfoModel.getDslEnv();
|
||||
Opt.ofBlankAble(dslEnv)
|
||||
.map(s -> UrlQuery.of(s, CharsetUtil.CHARSET_UTF_8))
|
||||
.map(UrlQuery::getQueryMap)
|
||||
.map(map -> {
|
||||
Map<String, String> map1 = MapUtil.newHashMap();
|
||||
for (Map.Entry<CharSequence, CharSequence> entry : map.entrySet()) {
|
||||
map1.put(StrUtil.toString(entry.getKey()), StrUtil.toString(entry.getValue()));
|
||||
}
|
||||
return map1;
|
||||
})
|
||||
.ifPresent(environmentMapBuilder::putStr);
|
||||
//
|
||||
environmentMapBuilder
|
||||
.putStr(scriptProcess.getScriptEnv())
|
||||
.put("PROJECT_ID", nodeProjectInfoModel.getId())
|
||||
.put("PROJECT_NAME", nodeProjectInfoModel.getName())
|
||||
.put("PROJECT_PATH", nodeProjectInfoModel.allLib());
|
||||
return environmentMapBuilder;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,207 @@
|
||||
package org.dromara.jpom.service.script;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.lang.Opt;
|
||||
import cn.hutool.core.lang.Tuple;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.net.url.UrlQuery;
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import org.dromara.jpom.JpomApplication;
|
||||
import org.dromara.jpom.common.Const;
|
||||
import org.dromara.jpom.common.IllegalArgument2Exception;
|
||||
import org.dromara.jpom.configuration.ProjectLogConfig;
|
||||
import org.dromara.jpom.model.EnvironmentMapBuilder;
|
||||
import org.dromara.jpom.model.data.DslYmlDto;
|
||||
import org.dromara.jpom.model.data.NodeProjectInfoModel;
|
||||
import org.dromara.jpom.model.data.NodeScriptModel;
|
||||
import org.dromara.jpom.script.DslScriptBuilder;
|
||||
import org.dromara.jpom.service.system.AgentWorkspaceEnvVarService;
|
||||
import org.dromara.jpom.socket.ConsoleCommandOp;
|
||||
import org.dromara.jpom.system.ExtConfigBean;
|
||||
import org.dromara.jpom.util.CommandUtil;
|
||||
import org.dromara.jpom.util.FileUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* @author bwcx_jzy
|
||||
* @since 23/12/30 030
|
||||
*/
|
||||
@Service
|
||||
public class DslScriptServer {
|
||||
|
||||
private final AgentWorkspaceEnvVarService agentWorkspaceEnvVarService;
|
||||
private final NodeScriptServer nodeScriptServer;
|
||||
private final ProjectLogConfig logConfig;
|
||||
private final JpomApplication jpomApplication;
|
||||
|
||||
public DslScriptServer(AgentWorkspaceEnvVarService agentWorkspaceEnvVarService,
|
||||
NodeScriptServer nodeScriptServer,
|
||||
ProjectLogConfig logConfig,
|
||||
JpomApplication jpomApplication) {
|
||||
this.agentWorkspaceEnvVarService = agentWorkspaceEnvVarService;
|
||||
this.nodeScriptServer = nodeScriptServer;
|
||||
this.logConfig = logConfig;
|
||||
this.jpomApplication = jpomApplication;
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步执行
|
||||
*
|
||||
* @param scriptProcess 脚本流程
|
||||
* @param log 日志
|
||||
*/
|
||||
public void run(DslYmlDto.BaseProcess scriptProcess, NodeProjectInfoModel nodeProjectInfoModel, String action, String log, boolean sync) throws Exception {
|
||||
DslScriptBuilder builder = this.create(scriptProcess, nodeProjectInfoModel, action, log);
|
||||
Future<?> execute = ThreadUtil.execAsync(builder);
|
||||
if (sync) {
|
||||
execute.get();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步执行
|
||||
*
|
||||
* @param scriptProcess 脚本流程
|
||||
*/
|
||||
public Tuple syncRun(DslYmlDto.BaseProcess scriptProcess, NodeProjectInfoModel nodeProjectInfoModel, String action) {
|
||||
try (DslScriptBuilder builder = this.create(scriptProcess, nodeProjectInfoModel, action, null)) {
|
||||
return builder.syncExecute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析流程脚本信息
|
||||
*
|
||||
* @param nodeProjectInfoModel 项目信息
|
||||
* @param dslYml dsl 配置信息
|
||||
* @param op 流程
|
||||
* @return data
|
||||
*/
|
||||
public Tuple resolveProcessScript(NodeProjectInfoModel nodeProjectInfoModel, DslYmlDto dslYml, ConsoleCommandOp op) {
|
||||
DslYmlDto.BaseProcess baseProcess = NodeProjectInfoModel.tryDslProcess(dslYml, op.name());
|
||||
return this.resolveProcessScript(nodeProjectInfoModel, baseProcess);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析流程脚本信息
|
||||
*
|
||||
* @param nodeProjectInfoModel 项目信息
|
||||
* @param scriptProcess 流程
|
||||
* @return data
|
||||
*/
|
||||
public Tuple resolveProcessScript(NodeProjectInfoModel nodeProjectInfoModel, DslYmlDto.BaseProcess scriptProcess) {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("status", false);
|
||||
if (scriptProcess == null) {
|
||||
jsonObject.put("msg", "流程不存在");
|
||||
return new Tuple(jsonObject, null);
|
||||
}
|
||||
String scriptId = scriptProcess.getScriptId();
|
||||
if (StrUtil.isEmpty(scriptId)) {
|
||||
jsonObject.put("msg", "请填写脚本模板id");
|
||||
return new Tuple(jsonObject, null);
|
||||
}
|
||||
//
|
||||
NodeScriptModel item = nodeScriptServer.getItem(scriptId);
|
||||
if (item != null) {
|
||||
// 脚本存在
|
||||
jsonObject.put("status", true);
|
||||
jsonObject.put("type", "script");
|
||||
jsonObject.put("scriptId", scriptId);
|
||||
return new Tuple(jsonObject, item);
|
||||
}
|
||||
File scriptFile = FileUtil.file(nodeProjectInfoModel.allLib(), scriptId);
|
||||
if (FileUtil.isFile(scriptFile)) {
|
||||
// 文件存在
|
||||
jsonObject.put("status", true);
|
||||
jsonObject.put("type", "file");
|
||||
jsonObject.put("scriptId", scriptId);
|
||||
return new Tuple(jsonObject, scriptFile);
|
||||
}
|
||||
jsonObject.put("msg", "脚本模版不存在:" + scriptId);
|
||||
return new Tuple(jsonObject, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建 DSL 执行器
|
||||
*
|
||||
* @param scriptProcess 脚本流程
|
||||
* @param nodeProjectInfoModel 项目
|
||||
* @param log 日志路径
|
||||
* @param action 具体操作
|
||||
*/
|
||||
private DslScriptBuilder create(DslYmlDto.BaseProcess scriptProcess, NodeProjectInfoModel nodeProjectInfoModel, String action, String log) {
|
||||
Tuple tuple = this.resolveProcessScript(nodeProjectInfoModel, scriptProcess);
|
||||
JSONObject jsonObject = tuple.get(0);
|
||||
// 判断状态
|
||||
boolean status = jsonObject.getBooleanValue("status");
|
||||
cn.hutool.core.lang.Assert.isTrue(status, () -> {
|
||||
String msg = jsonObject.getString("msg");
|
||||
return new IllegalArgument2Exception(msg);
|
||||
});
|
||||
String type = jsonObject.getString("type");
|
||||
EnvironmentMapBuilder environment = this.environment(nodeProjectInfoModel, scriptProcess);
|
||||
File scriptFile;
|
||||
boolean autoDelete = false;
|
||||
if (StrUtil.equals(type, "file")) {
|
||||
scriptFile = tuple.get(1);
|
||||
} else {
|
||||
NodeScriptModel item = tuple.get(1);
|
||||
scriptFile = this.initScriptFile(item);
|
||||
// 系统生成的脚本需要自动删除
|
||||
autoDelete = true;
|
||||
}
|
||||
DslScriptBuilder builder = new DslScriptBuilder(action, environment, scriptProcess.getScriptArgs(), log, logConfig.getFileCharset());
|
||||
builder.setScriptFile(scriptFile);
|
||||
builder.setAutoDelete(autoDelete);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建脚本文件
|
||||
*
|
||||
* @param scriptModel 脚本对象
|
||||
* @return file
|
||||
*/
|
||||
private File initScriptFile(NodeScriptModel scriptModel) {
|
||||
String dataPath = jpomApplication.getDataPath();
|
||||
File scriptFile = FileUtil.file(dataPath, Const.SCRIPT_RUN_CACHE_DIRECTORY, StrUtil.format("{}.{}", IdUtil.fastSimpleUUID(), CommandUtil.SUFFIX));
|
||||
// 替换内容
|
||||
String context = scriptModel.getContext();
|
||||
FileUtils.writeScript(context, scriptFile, ExtConfigBean.getConsoleLogCharset());
|
||||
return scriptFile;
|
||||
}
|
||||
|
||||
private EnvironmentMapBuilder environment(NodeProjectInfoModel nodeProjectInfoModel, DslYmlDto.BaseProcess scriptProcess) {
|
||||
//
|
||||
EnvironmentMapBuilder environmentMapBuilder = agentWorkspaceEnvVarService.getEnv(nodeProjectInfoModel.getWorkspaceId());
|
||||
// 项目配置的环境变量
|
||||
String dslEnv = nodeProjectInfoModel.getDslEnv();
|
||||
Opt.ofBlankAble(dslEnv)
|
||||
.map(s -> UrlQuery.of(s, CharsetUtil.CHARSET_UTF_8))
|
||||
.map(UrlQuery::getQueryMap)
|
||||
.map(map -> {
|
||||
Map<String, String> map1 = MapUtil.newHashMap();
|
||||
for (Map.Entry<CharSequence, CharSequence> entry : map.entrySet()) {
|
||||
map1.put(StrUtil.toString(entry.getKey()), StrUtil.toString(entry.getValue()));
|
||||
}
|
||||
return map1;
|
||||
})
|
||||
.ifPresent(environmentMapBuilder::putStr);
|
||||
//
|
||||
environmentMapBuilder
|
||||
.putStr(scriptProcess.getScriptEnv())
|
||||
.put("PROJECT_ID", nodeProjectInfoModel.getId())
|
||||
.put("PROJECT_NAME", nodeProjectInfoModel.getName())
|
||||
.put("PROJECT_PATH", nodeProjectInfoModel.allLib());
|
||||
return environmentMapBuilder;
|
||||
}
|
||||
}
|
@ -147,7 +147,7 @@ public class AgentWebSocketConsoleHandle extends BaseAgentWebSocketHandle {
|
||||
RunMode runMode = nodeProjectInfoModel.getRunMode();
|
||||
if (runMode == RunMode.Dsl) {
|
||||
// 判断是否可以执行 reload 事件
|
||||
DslYmlDto dslYmlDto = nodeProjectInfoModel.dslConfig();
|
||||
DslYmlDto dslYmlDto = nodeProjectInfoModel.mustDslConfig();
|
||||
boolean b = dslYmlDto.hasRunProcess(ConsoleCommandOp.reload.name());
|
||||
json.put("canReload", b);
|
||||
}
|
||||
|
@ -216,13 +216,14 @@ public class JpomApplication implements DisposableBean, InitializingBean {
|
||||
if (SystemUtil.getOsInfo().isWindows()) {
|
||||
//String result = CommandUtil.execSystemCommand(command, scriptFile.getParentFile());
|
||||
//log.debug("windows restart {}", result);
|
||||
CommandUtil.asyncExeLocalCommand(parentFile, "start /b" + command);
|
||||
CommandUtil.asyncExeLocalCommand("start /b" + command, parentFile);
|
||||
} else {
|
||||
String jpomService = SystemUtil.get("JPOM_SERVICE");
|
||||
if (StrUtil.isEmpty(jpomService)) {
|
||||
CommandUtil.asyncExeLocalCommand(parentFile, command);
|
||||
CommandUtil.asyncExeLocalCommand(command, parentFile);
|
||||
} else {
|
||||
CommandUtil.asyncExeLocalCommand(parentFile, "systemctl restart " + jpomService);
|
||||
// 使用了服务
|
||||
CommandUtil.asyncExeLocalCommand("systemctl restart " + jpomService, parentFile);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
@ -39,6 +39,9 @@ public enum ConsoleCommandOp {
|
||||
stop(true),
|
||||
restart(true),
|
||||
status,
|
||||
/**
|
||||
* 重载
|
||||
*/
|
||||
reload(true),
|
||||
/**
|
||||
* 运行日志
|
||||
@ -49,7 +52,9 @@ public enum ConsoleCommandOp {
|
||||
*/
|
||||
heart,
|
||||
;
|
||||
|
||||
/**
|
||||
* 是否支持手动操作(执行)
|
||||
*/
|
||||
private final boolean canOpt;
|
||||
|
||||
ConsoleCommandOp() {
|
||||
|
@ -266,7 +266,7 @@ public class CommandUtil {
|
||||
* @param command 命令
|
||||
* @throws IOException 异常
|
||||
*/
|
||||
public static void asyncExeLocalCommand(File file, String command) throws Exception {
|
||||
public static void asyncExeLocalCommand(String command, File file) throws Exception {
|
||||
String newCommand = StrUtil.replace(command, StrUtil.CRLF, StrUtil.SPACE);
|
||||
newCommand = StrUtil.replace(newCommand, StrUtil.LF, StrUtil.SPACE);
|
||||
//
|
||||
|
@ -30,7 +30,6 @@ import org.dromara.jpom.common.JpomManifest;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -114,11 +113,15 @@ public class JvmUtil {
|
||||
public static Integer getPidByTag(String tag) {
|
||||
String execSystemCommand = CommandUtil.execSystemCommand("jps -mv");
|
||||
List<String> list = StrSplitter.splitTrim(execSystemCommand, StrUtil.LF, true);
|
||||
Optional<String> any = list.stream().filter(s -> checkCommandLineIsJpom(s, tag)).map(s -> {
|
||||
List<String> split = StrUtil.split(s, StrUtil.SPACE);
|
||||
return CollUtil.getFirst(split);
|
||||
}).findAny();
|
||||
return any.map(Convert::toInt).orElse(null);
|
||||
return list.stream()
|
||||
.filter(s -> checkCommandLineIsJpom(s, tag))
|
||||
.map(s -> {
|
||||
List<String> split = StrUtil.split(s, StrUtil.SPACE);
|
||||
return CollUtil.getFirst(split);
|
||||
})
|
||||
.findAny()
|
||||
.map(Convert::toInt)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -34,6 +34,7 @@ import cn.hutool.db.Page;
|
||||
import cn.hutool.db.PageResult;
|
||||
import cn.hutool.db.ds.DSFactory;
|
||||
import cn.hutool.db.sql.Condition;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.jpom.model.PageResultDto;
|
||||
import org.dromara.jpom.system.JpomRuntimeException;
|
||||
@ -69,6 +70,7 @@ public abstract class BaseDbCommonService<T> {
|
||||
/**
|
||||
* 表名
|
||||
*/
|
||||
@Getter
|
||||
protected final String tableName;
|
||||
protected final Class<T> tClass;
|
||||
|
||||
@ -81,10 +83,6 @@ public abstract class BaseDbCommonService<T> {
|
||||
this.tableName = annotation.value();
|
||||
}
|
||||
|
||||
public String getTableName() {
|
||||
return tableName;
|
||||
}
|
||||
|
||||
protected DataSource getDataSource() {
|
||||
DSFactory dsFactory = StorageServiceFactory.get().getDsFactory();
|
||||
return dsFactory.getDataSource();
|
||||
|
@ -95,10 +95,6 @@ export default {
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.node-full-content {
|
||||
min-height: calc(100vh - 130px) !important;
|
||||
}
|
||||
|
||||
.globalLoading {
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
|
@ -498,6 +498,15 @@ export function getProjectGroupAll() {
|
||||
*/
|
||||
export const runModeList = ["Dsl", "ClassPath", "Jar", "JarWar", "JavaExtDirsCp", "File"];
|
||||
|
||||
export const runModeObj = {
|
||||
Dsl: "自定义脚本项目(python、nodejs、go、接口探活、es)【推荐】",
|
||||
ClassPath: "Java 项目(java -classpath)",
|
||||
Jar: "Java 项目(java -jar xxx)",
|
||||
JavaExtDirsCp: "Java 项目(java -Djava.ext.dirs=lib -cp conf:run.jar $MAIN_CLASS)",
|
||||
File: "静态文件项目(前端、日志等)",
|
||||
JarWar: "Java 项目(java -jar Springboot war)【不推荐】",
|
||||
};
|
||||
|
||||
/**
|
||||
* java 项目的运行模式
|
||||
*/
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 布局 -->
|
||||
<a-layout class="file-layout node-full-content">
|
||||
<a-layout class="file-layout">
|
||||
<!-- 目录树 -->
|
||||
<a-layout-sider theme="light" class="sider" width="25%">
|
||||
<div class="dir-container">
|
||||
|
@ -1,302 +0,0 @@
|
||||
<template>
|
||||
<div class="node-full-content">
|
||||
<!-- 数据表格 -->
|
||||
<a-table size="middle" :data-source="list" :columns="columns" @change="changePage" :pagination="pagination" bordered rowKey="id">
|
||||
<template slot="title">
|
||||
<a-space>
|
||||
<a-input v-model="listQuery['%name%']" placeholder="名称" allowClear class="search-input-item" />
|
||||
<a-tooltip title="按住 Ctr 或者 Alt/Option 键点击按钮快速回到第一页">
|
||||
<a-button type="primary" :loading="loading" @click="loadData">搜索</a-button>
|
||||
</a-tooltip>
|
||||
<a-button type="primary" @click="handleAdd">新增</a-button>
|
||||
|
||||
<a-tooltip placement="topLeft" title="清除服务端缓存节点所有的脚步模版信息并重新同步">
|
||||
<a-icon @click="sync()" type="sync" spin />
|
||||
</a-tooltip>
|
||||
</a-space>
|
||||
</template>
|
||||
<a-tooltip slot="tooltip" slot-scope="text" placement="topLeft" :title="text">
|
||||
<span>{{ text }}</span>
|
||||
</a-tooltip>
|
||||
<template slot="global" slot-scope="text">
|
||||
<a-tag v-if="text === 'GLOBAL'">全局</a-tag>
|
||||
<a-tag v-else>工作空间</a-tag>
|
||||
</template>
|
||||
|
||||
<template slot="operation" slot-scope="text, record">
|
||||
<a-space>
|
||||
<a-button size="small" type="primary" @click="handleExec(record)">执行</a-button>
|
||||
<a-button size="small" :type="`${record.scriptType === 'server-sync' ? '' : 'primary'}`" @click="handleEdit(record)">{{ record.scriptType === "server-sync" ? "查看" : " 编辑" }}</a-button>
|
||||
<a-tooltip :title="`${record.scriptType === 'server-sync' ? '服务端分发同步的脚本不能直接删除,需要到服务端去操作' : '删除'}`">
|
||||
<a-button size="small" :disabled="record.scriptType === 'server-sync'" type="danger" @click="handleDelete(record)">删除</a-button>
|
||||
</a-tooltip>
|
||||
</a-space>
|
||||
</template>
|
||||
</a-table>
|
||||
<!-- 编辑区 -->
|
||||
<a-modal destroyOnClose v-model="editScriptVisible" title="编辑 Script" @ok="handleEditScriptOk" :maskClosable="false" width="80vw">
|
||||
<a-form-model ref="editScriptForm" :rules="rules" :model="temp" :label-col="{ span: 3 }" :wrapper-col="{ span: 18 }">
|
||||
<a-alert v-if="this.temp.scriptType === 'server-sync'" message="服务端同步的脚本不能在此修改" banner />
|
||||
<a-form-model-item v-if="temp.id" label="ScriptId" prop="id">
|
||||
<a-input v-model="temp.id" disabled readOnly />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="Script 名称" prop="name">
|
||||
<a-input :maxLength="50" v-model="temp.name" placeholder="名称" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="Script 内容" prop="context">
|
||||
<div style="height: 40vh; overflow-y: scroll">
|
||||
<code-editor v-model="temp.context" :options="{ mode: 'shell', tabSize: 2, theme: 'abcdef' }"></code-editor>
|
||||
</div>
|
||||
</a-form-model-item>
|
||||
<!-- <a-form-model-item label="默认参数" prop="defArgs">
|
||||
<a-input v-model="temp.defArgs" placeholder="默认参数" />
|
||||
</a-form-model-item> -->
|
||||
<a-form-model-item label="默认参数">
|
||||
<div v-for="(item, index) in commandParams" :key="item.key">
|
||||
<a-row type="flex" justify="center" align="middle">
|
||||
<a-col :span="22">
|
||||
<a-input :addon-before="`参数${index + 1}描述`" v-model="item.desc" placeholder="参数描述,参数描述没有实际作用,仅是用于提示参数的含义" />
|
||||
<a-input :addon-before="`参数${index + 1}值`" v-model="item.value" placeholder="参数值,添加默认参数后在手动执行脚本时需要填写参数值" />
|
||||
</a-col>
|
||||
<a-col :span="2">
|
||||
<a-row type="flex" justify="center" align="middle">
|
||||
<a-col>
|
||||
<a-icon @click="() => commandParams.splice(index, 1)" type="minus-circle" style="color: #ff0000" />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-divider style="margin: 5px 0" />
|
||||
</div>
|
||||
|
||||
<a-button type="primary" @click="() => commandParams.push({})">添加参数</a-button>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="共享" prop="global">
|
||||
<a-radio-group v-model="temp.global">
|
||||
<a-radio :value="true"> 全局</a-radio>
|
||||
<a-radio :value="false"> 当前工作空间</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="定时执行" prop="autoExecCron">
|
||||
<a-auto-complete v-model="temp.autoExecCron" placeholder="如果需要定时自动执行则填写,cron 表达式.默认未开启秒级别,需要去修改配置文件中:[system.timerMatchSecond])" option-label-prop="value">
|
||||
<template slot="dataSource">
|
||||
<a-select-opt-group v-for="group in cronDataSource" :key="group.title">
|
||||
<span slot="label">
|
||||
{{ group.title }}
|
||||
</span>
|
||||
<a-select-option v-for="opt in group.children" :key="opt.title" :value="opt.value"> {{ opt.title }} {{ opt.value }} </a-select-option>
|
||||
</a-select-opt-group>
|
||||
</template>
|
||||
</a-auto-complete>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="描述" prop="description">
|
||||
<a-input :maxLength="200" v-model="temp.description" type="textarea" :rows="3" style="resize: none" placeholder="详细描述" />
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</a-modal>
|
||||
<!-- 脚本控制台组件 -->
|
||||
<a-drawer destroyOnClose :title="drawerTitle" placement="right" width="85vw" :visible="drawerConsoleVisible" @close="onConsoleClose">
|
||||
<script-console v-if="drawerConsoleVisible" :nodeId="node.id" :defArgs="temp.defArgs" :id="temp.id" :scriptId="temp.scriptId" />
|
||||
</a-drawer>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { getScriptList, editScript, deleteScript, itemScript, syncScript } from "@/api/node-other";
|
||||
import codeEditor from "@/components/codeEditor";
|
||||
import ScriptConsole from "./script-console";
|
||||
import { CRON_DATA_SOURCE, COMPUTED_PAGINATION, CHANGE_PAGE, PAGE_DEFAULT_LIST_QUERY, parseTime } from "@/utils/const";
|
||||
export default {
|
||||
components: {
|
||||
ScriptConsole,
|
||||
codeEditor,
|
||||
},
|
||||
props: {
|
||||
node: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
listQuery: Object.assign({}, PAGE_DEFAULT_LIST_QUERY),
|
||||
list: [],
|
||||
temp: {},
|
||||
cronDataSource: CRON_DATA_SOURCE,
|
||||
editScriptVisible: false,
|
||||
drawerTitle: "",
|
||||
drawerConsoleVisible: false,
|
||||
|
||||
columns: [
|
||||
{ title: "Script ID", dataIndex: "scriptId", width: 150, ellipsis: true, scopedSlots: { customRender: "tooltip" } },
|
||||
{ title: "名称", dataIndex: "name", ellipsis: true, width: 200, scopedSlots: { customRender: "tooltip" } },
|
||||
{ title: "定时执行", dataIndex: "autoExecCron", ellipsis: true, width: "120px", scopedSlots: { customRender: "autoExecCron" } },
|
||||
{ title: "共享", dataIndex: "workspaceId", ellipsis: true, scopedSlots: { customRender: "global" }, width: "90px" },
|
||||
{
|
||||
title: "创建时间",
|
||||
dataIndex: "createTimeMillis",
|
||||
ellipsis: true,
|
||||
sorter: true,
|
||||
customRender: (text) => parseTime(text),
|
||||
width: "170px",
|
||||
},
|
||||
{
|
||||
title: "修改时间",
|
||||
dataIndex: "modifyTimeMillis",
|
||||
width: "170px",
|
||||
ellipsis: true,
|
||||
sorter: true,
|
||||
customRender: (text) => parseTime(text),
|
||||
},
|
||||
{ title: "创建人", dataIndex: "createUser", ellipsis: true, scopedSlots: { customRender: "tooltip" }, width: "120px" },
|
||||
{ title: "修改人", dataIndex: "modifyUser", ellipsis: true, scopedSlots: { customRender: "modifyUser" }, width: "120px" },
|
||||
// { title: "最后操作人", dataIndex: "lastRunUser", ellipsis: true, width: 150, scopedSlots: { customRender: "lastRunUser" } },
|
||||
{ title: "操作", dataIndex: "operation", align: "center", scopedSlots: { customRender: "operation" }, fixed: "right", width: "180px" },
|
||||
],
|
||||
rules: {
|
||||
name: [{ required: true, message: "请输入脚本名称", trigger: "blur" }],
|
||||
context: [{ required: true, message: "请输入脚本内容", trigger: "blur" }],
|
||||
},
|
||||
commandParams: [],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
pagination() {
|
||||
return COMPUTED_PAGINATION(this.listQuery);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// this.calcTableHeight();
|
||||
this.loadData();
|
||||
},
|
||||
methods: {
|
||||
// 加载数据
|
||||
loadData(pointerEvent) {
|
||||
this.listQuery.page = pointerEvent?.altKey || pointerEvent?.ctrlKey ? 1 : this.listQuery.page;
|
||||
this.loading = true;
|
||||
getScriptList({ ...this.listQuery, nodeId: this.node.id }).then((res) => {
|
||||
if (res.code === 200) {
|
||||
this.list = res.data.result;
|
||||
this.listQuery.total = res.data.total;
|
||||
}
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
parseTime,
|
||||
// 添加
|
||||
handleAdd() {
|
||||
this.temp = {
|
||||
type: "add",
|
||||
};
|
||||
this.commandParams = [];
|
||||
this.editScriptVisible = true;
|
||||
},
|
||||
// 修改
|
||||
handleEdit(record) {
|
||||
itemScript({
|
||||
id: record.scriptId,
|
||||
nodeId: this.node.id,
|
||||
}).then((res) => {
|
||||
this.temp = Object.assign({}, res.data, { global: res.data.workspaceId === "GLOBAL", workspaceId: "" });
|
||||
this.commandParams = this.temp.defArgs ? JSON.parse(this.temp.defArgs) : [];
|
||||
//
|
||||
this.editScriptVisible = true;
|
||||
});
|
||||
},
|
||||
// 提交 Script 数据
|
||||
handleEditScriptOk() {
|
||||
if (this.temp.scriptType === "server-sync") {
|
||||
this.$notification.warning({
|
||||
message: "服务端同步的脚本不能在此修改",
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (this.commandParams && this.commandParams.length > 0) {
|
||||
for (let i = 0; i < this.commandParams.length; i++) {
|
||||
if (!this.commandParams[i].desc) {
|
||||
this.$notification.error({
|
||||
message: "请填写第" + (i + 1) + "个参数的描述",
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
this.temp.defArgs = JSON.stringify(this.commandParams);
|
||||
} else {
|
||||
this.temp.defArgs = "";
|
||||
}
|
||||
// 检验表单
|
||||
this.$refs["editScriptForm"].validate((valid) => {
|
||||
if (!valid) {
|
||||
return false;
|
||||
}
|
||||
this.temp.nodeId = this.node.id;
|
||||
// 提交数据
|
||||
editScript(this.temp).then((res) => {
|
||||
if (res.code === 200) {
|
||||
// 成功
|
||||
this.$notification.success({
|
||||
message: res.msg,
|
||||
});
|
||||
|
||||
this.editScriptVisible = false;
|
||||
this.loadData();
|
||||
this.$refs["editScriptForm"].resetFields();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
handleDelete(record) {
|
||||
this.$confirm({
|
||||
title: "系统提示",
|
||||
content: "真的要删除脚本么?",
|
||||
okText: "确认",
|
||||
cancelText: "取消",
|
||||
onOk: () => {
|
||||
// 组装参数
|
||||
const params = {
|
||||
nodeId: this.node.id,
|
||||
id: record.scriptId,
|
||||
};
|
||||
// 删除
|
||||
deleteScript(params).then((res) => {
|
||||
if (res.code === 200) {
|
||||
this.$notification.success({
|
||||
message: res.msg,
|
||||
});
|
||||
this.loadData();
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
// 执行 Script
|
||||
handleExec(record) {
|
||||
this.temp = Object.assign({}, record);
|
||||
this.drawerTitle = `控制台(${this.temp.name})`;
|
||||
this.drawerConsoleVisible = true;
|
||||
},
|
||||
// 关闭 console
|
||||
onConsoleClose() {
|
||||
this.drawerConsoleVisible = false;
|
||||
},
|
||||
|
||||
// 分页、排序、筛选变化时触发
|
||||
changePage(pagination, filters, sorter) {
|
||||
this.listQuery = CHANGE_PAGE(this.listQuery, { pagination, sorter });
|
||||
this.loadData();
|
||||
},
|
||||
sync() {
|
||||
syncScript({
|
||||
nodeId: this.node.id,
|
||||
}).then((res) => {
|
||||
if (res.code == 200) {
|
||||
this.$notification.success({
|
||||
message: res.msg,
|
||||
});
|
||||
this.loadData();
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped></style>
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="node-full-content">
|
||||
<div>
|
||||
<!-- 数据表格 -->
|
||||
<a-table :data-source="list" size="middle" :columns="columns" @change="changePage" :pagination="pagination" bordered rowKey="id">
|
||||
<template slot="title">
|
||||
|
@ -10,33 +10,60 @@
|
||||
<a-button size="small" v-if="project.runMode === 'Dsl'" :disabled="!canReload" :loading="optButtonLoading" type="primary" @click="reload">重载</a-button>
|
||||
|
||||
<a-button size="small" type="primary" @click="goFile">文件管理</a-button>
|
||||
|
||||
<a-dropdown>
|
||||
<!-- <a type="link" class="ant-dropdown-link"> 更多<a-icon type="down" /> </a> -->
|
||||
<a-button
|
||||
size="small"
|
||||
@click="
|
||||
(e) => {
|
||||
e.preventDefault();
|
||||
handleLogBack();
|
||||
}
|
||||
"
|
||||
>
|
||||
<!-- <a-tag> -->
|
||||
日志大小: {{ project.logSize || "-" }}
|
||||
<!-- 更多 -->
|
||||
<a-icon type="fullscreen" />
|
||||
<!-- </a-tag> -->
|
||||
</a-button>
|
||||
<!-- <a-menu slot="overlay">
|
||||
<a-menu-item>
|
||||
<a-button type="primary" size="small" :disabled="!project.logSize" @click="handleDownload">导出日志</a-button>
|
||||
<a-dropdown v-if="project.dslProcessInfo">
|
||||
<a-menu slot="overlay">
|
||||
<a-menu-item v-for="(item, index) in project.dslProcessInfo" :key="index">
|
||||
<template v-if="item.status">
|
||||
<a-tag>
|
||||
{{ item.process }}
|
||||
</a-tag>
|
||||
<template v-if="item.type === 'file'">项目文件 {{ item.scriptId }} </template>
|
||||
<template v-else-if="item.type === 'script'">
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
icon="edit"
|
||||
@click="
|
||||
() => {
|
||||
temp = { scriptId: item.scriptId };
|
||||
editScriptVisible = true;
|
||||
}
|
||||
"
|
||||
>
|
||||
节点脚本
|
||||
</a-button>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<a-space>
|
||||
<a-tag>
|
||||
{{ item.process }}
|
||||
</a-tag>
|
||||
<a-icon type="exclamation-circle" />
|
||||
{{ item.msg }}
|
||||
</a-space>
|
||||
</template>
|
||||
</a-menu-item>
|
||||
<a-menu-item>
|
||||
<a-button type="primary" size="small" @click="handleLogBack">备份列表</a-button>
|
||||
</a-menu-item>
|
||||
</a-menu> -->
|
||||
</a-menu>
|
||||
<a-button size="small" type="primary"> 关联脚本 <a-icon type="down" /> </a-button>
|
||||
</a-dropdown>
|
||||
<a-button
|
||||
size="small"
|
||||
@click="
|
||||
(e) => {
|
||||
e.preventDefault();
|
||||
handleLogBack();
|
||||
}
|
||||
"
|
||||
>
|
||||
<!-- <a-tag> -->
|
||||
日志大小: {{ project.logSize || "-" }}
|
||||
<!-- 更多 -->
|
||||
<a-icon type="fullscreen" />
|
||||
<!-- </a-tag> -->
|
||||
</a-button>
|
||||
|
||||
|
|
||||
</a-space>
|
||||
</template>
|
||||
</log-view>
|
||||
@ -44,6 +71,17 @@
|
||||
<a-modal destroyOnClose v-model="lobbackVisible" title="日志备份列表" width="850px" :footer="null" :maskClosable="false">
|
||||
<ProjectLog v-if="lobbackVisible" :nodeId="this.nodeId" :projectId="this.projectId"></ProjectLog>
|
||||
</a-modal>
|
||||
<!-- 编辑区 -->
|
||||
<ScriptEdit
|
||||
v-if="editScriptVisible"
|
||||
:nodeId="this.nodeId"
|
||||
:scriptId="temp.scriptId"
|
||||
@close="
|
||||
() => {
|
||||
editScriptVisible = false;
|
||||
}
|
||||
"
|
||||
></ScriptEdit>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
@ -51,12 +89,13 @@ import { getProjectData, getProjectLogSize } from "@/api/node-project";
|
||||
import { mapGetters } from "vuex";
|
||||
import { getWebSocketUrl } from "@/utils/const";
|
||||
import LogView from "@/components/logView/index2";
|
||||
import ProjectLog from "./project-log.vue";
|
||||
|
||||
import ProjectLog from "./project-log";
|
||||
import ScriptEdit from "@/pages/node/script-edit";
|
||||
export default {
|
||||
components: {
|
||||
LogView,
|
||||
ProjectLog,
|
||||
ScriptEdit,
|
||||
},
|
||||
props: {
|
||||
nodeId: {
|
||||
@ -79,6 +118,7 @@ export default {
|
||||
lobbackVisible: false,
|
||||
canReload: false,
|
||||
heart: null,
|
||||
editScriptVisible: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
@ -52,7 +52,16 @@
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<a-select v-model="temp.runMode" placeholder="请选择运行方式">
|
||||
<a-select-option v-for="runMode in runModeList" :key="runMode">{{ runMode }}</a-select-option>
|
||||
<a-select-option v-for="(val, key) in runModeObj" :key="key">
|
||||
<template v-if="val.indexOf('不推荐') > -1">
|
||||
<s>
|
||||
<b>[{{ key }}]</b> {{ val }}
|
||||
</s>
|
||||
</template>
|
||||
<template v-else>
|
||||
<b>[{{ key }}]</b> {{ val }}
|
||||
</template>
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item prop="whitelistDirectory" class="jpom-node-project-whitelist">
|
||||
@ -178,7 +187,9 @@
|
||||
<a-icon v-show="temp.type !== 'edit'" type="question-circle" theme="filled" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<template #help>非服务器开机自启,如需开机自启建议配置<b>插件端开机自启</b>并开启此开关</template>
|
||||
<a-switch v-model="temp.autoStart" checked-children="开" un-checked-children="关" />
|
||||
插件端启动时自动检查项目如未启动将尝试启动
|
||||
</a-form-model-item>
|
||||
<a-form-model-item v-if="temp.runMode === 'Dsl'" prop="dslEnv" label="DSL环境变量">
|
||||
<a-input v-model="temp.dslEnv" placeholder="DSL环境变量,如:key1=values1&keyvalue2" />
|
||||
@ -244,6 +255,7 @@ import {
|
||||
getProjectData,
|
||||
javaModes,
|
||||
// nodeJudgeLibExist,
|
||||
runModeObj,
|
||||
noFileModes,
|
||||
runModeList,
|
||||
getProjectGroupAll,
|
||||
@ -269,9 +281,10 @@ export default {
|
||||
return {
|
||||
accessList: [],
|
||||
groupList: [],
|
||||
runModeList: runModeList,
|
||||
javaModes: javaModes,
|
||||
noFileModes: noFileModes,
|
||||
runModeObj,
|
||||
runModeList,
|
||||
javaModes,
|
||||
noFileModes,
|
||||
PROJECT_DSL_DEFATUL,
|
||||
configDir: false,
|
||||
temp: {},
|
||||
|
@ -18,7 +18,7 @@
|
||||
</a-table>
|
||||
</div>
|
||||
<!-- 布局 -->
|
||||
<a-layout v-show="!viewList" class="file-layout node-full-content">
|
||||
<a-layout v-show="!viewList" class="file-layout">
|
||||
<!-- 目录树 -->
|
||||
<a-layout-sider theme="light" class="sider" width="25%">
|
||||
<div class="dir-container">
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 布局 -->
|
||||
<a-layout class="file-layout node-full-content">
|
||||
<a-layout class="file-layout">
|
||||
<!-- 目录树 -->
|
||||
<a-layout-sider theme="light" class="sider" width="25%">
|
||||
<div class="dir-container">
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="node-full-content">
|
||||
<div class="">
|
||||
<a-tabs default-active-key="1" tab-position="left">
|
||||
<a-tab-pane key="1" tab="缓存信息">
|
||||
<a-alert message="请勿手动删除数据目录下面文件,如果需要删除需要提前备份或者已经确定对应文件弃用后才能删除" style="margin-top: 10px; margin-bottom: 40px" banner />
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="node-full-content">
|
||||
<div class="">
|
||||
<a-form-model ref="editForm" :model="temp">
|
||||
<a-alert v-if="temp.file" :message="`配置文件路径:${temp.file}`" style="margin-top: 10px; margin-bottom: 20px" banner />
|
||||
<a-form-model-item class="node-content-config">
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<a-layout class="log-layout node-full-content">
|
||||
<a-layout class="log-layout">
|
||||
<!-- 侧边栏 文件树 -->
|
||||
<a-layout-sider theme="light" class="log-sider jpom-node-log-tree" width="20%">
|
||||
<a-empty v-if="list.length === 0" />
|
||||
|
@ -1,27 +0,0 @@
|
||||
<template>
|
||||
<div class="node-full-content">
|
||||
<machine-info :nodeId="this.node.id"></machine-info>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import machineInfo from "@/pages/system/assets/machine/machine-info";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
machineInfo,
|
||||
},
|
||||
props: {
|
||||
node: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
mounted() {},
|
||||
destroyed() {},
|
||||
watch: {},
|
||||
methods: {},
|
||||
};
|
||||
</script>
|
||||
<style scoped></style>
|
195
web-vue/src/pages/node/script-edit.vue
Normal file
195
web-vue/src/pages/node/script-edit.vue
Normal file
@ -0,0 +1,195 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-modal
|
||||
destroyOnClose
|
||||
:visible="true"
|
||||
title="编辑 Script"
|
||||
@ok="handleEditScriptOk"
|
||||
:maskClosable="false"
|
||||
width="80vw"
|
||||
@cancel="
|
||||
() => {
|
||||
$emit('close');
|
||||
}
|
||||
"
|
||||
>
|
||||
<a-form-model ref="editScriptForm" :rules="rules" :model="temp" :label-col="{ span: 3 }" :wrapper-col="{ span: 19 }">
|
||||
<a-alert v-if="this.temp.scriptType === 'server-sync'" message="服务端同步的脚本不能在此修改" banner />
|
||||
<a-form-model-item label="选择节点">
|
||||
<a-select v-model="temp.nodeId" :disabled="!!temp.nodeId" allowClear placeholder="请选择节点">
|
||||
<a-select-option v-for="node in nodeList" :key="node.id">{{ node.name }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-model-item>
|
||||
<template v-if="temp.nodeId">
|
||||
<a-form-model-item label="Script 名称" prop="name">
|
||||
<a-input v-model="temp.name" placeholder="名称" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="Script 内容" prop="context">
|
||||
<div style="height: 40vh; overflow-y: scroll">
|
||||
<code-editor v-model="temp.context" :options="{ mode: 'shell', tabSize: 2, theme: 'abcdef' }"></code-editor>
|
||||
</div>
|
||||
</a-form-model-item>
|
||||
<!-- <a-form-model-item label="默认参数" prop="defArgs">
|
||||
<a-input v-model="temp.defArgs" placeholder="默认参数" />
|
||||
</a-form-model-item> -->
|
||||
<a-form-model-item label="默认参数">
|
||||
<div v-for="(item, index) in commandParams" :key="item.key">
|
||||
<a-row type="flex" justify="center" align="middle">
|
||||
<a-col :span="22">
|
||||
<a-input :addon-before="`参数${index + 1}描述`" v-model="item.desc" placeholder="参数描述,参数描述没有实际作用,仅是用于提示参数的含义" />
|
||||
<a-input :addon-before="`参数${index + 1}值`" v-model="item.value" placeholder="参数值,添加默认参数后在手动执行脚本时需要填写参数值" />
|
||||
</a-col>
|
||||
<a-col :span="2">
|
||||
<a-row type="flex" justify="center" align="middle">
|
||||
<a-col>
|
||||
<a-icon @click="() => commandParams.splice(index, 1)" type="minus-circle" style="color: #ff0000" />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-divider style="margin: 5px 0" />
|
||||
</div>
|
||||
|
||||
<a-button type="primary" @click="() => commandParams.push({})">添加参数</a-button>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="共享" prop="global">
|
||||
<a-radio-group v-model="temp.global">
|
||||
<a-radio :value="true"> 全局</a-radio>
|
||||
<a-radio :value="false"> 当前工作空间</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="定时执行" prop="autoExecCron">
|
||||
<a-auto-complete
|
||||
v-model="temp.autoExecCron"
|
||||
placeholder="如果需要定时自动执行则填写,cron 表达式.默认未开启秒级别,需要去修改配置文件中:[system.timerMatchSecond])"
|
||||
option-label-prop="value"
|
||||
>
|
||||
<template slot="dataSource">
|
||||
<a-select-opt-group v-for="group in cronDataSource" :key="group.title">
|
||||
<span slot="label">
|
||||
{{ group.title }}
|
||||
</span>
|
||||
<a-select-option v-for="opt in group.children" :key="opt.title" :value="opt.value"> {{ opt.title }} {{ opt.value }} </a-select-option>
|
||||
</a-select-opt-group>
|
||||
</template>
|
||||
</a-auto-complete>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="描述" prop="description">
|
||||
<a-input v-model="temp.description" type="textarea" :rows="3" style="resize: none" placeholder="详细描述" />
|
||||
</a-form-model-item>
|
||||
</template>
|
||||
</a-form-model>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import codeEditor from "@/components/codeEditor";
|
||||
import { editScript, itemScript } from "@/api/node-other";
|
||||
import { CRON_DATA_SOURCE } from "@/utils/const";
|
||||
import { getNodeListAll } from "@/api/node";
|
||||
export default {
|
||||
components: {
|
||||
codeEditor,
|
||||
},
|
||||
props: {
|
||||
nodeId: {
|
||||
type: String,
|
||||
default: undefined,
|
||||
},
|
||||
scriptId: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
temp: {},
|
||||
cronDataSource: CRON_DATA_SOURCE,
|
||||
commandParams: [],
|
||||
nodeList: [],
|
||||
rules: {
|
||||
name: [{ required: true, message: "请输入脚本名称", trigger: "blur" }],
|
||||
context: [{ required: true, message: "请输入脚本内容", trigger: "blur" }],
|
||||
},
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
// 查询节点
|
||||
getNodeListAll().then((res) => {
|
||||
if (res.code === 200 && res.data) {
|
||||
this.nodeList = res.data;
|
||||
// res.data.forEach((item) => {
|
||||
// this.nodeMap[item.id] = item.name;
|
||||
// });
|
||||
}
|
||||
this.handleEdit();
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
// 修改
|
||||
handleEdit() {
|
||||
this.$refs["editScriptForm"]?.resetFields();
|
||||
if (this.scriptId && this.nodeId) {
|
||||
itemScript({
|
||||
id: this.scriptId,
|
||||
nodeId: this.nodeId,
|
||||
}).then((res) => {
|
||||
if (res.code === 200) {
|
||||
this.temp = Object.assign({}, res.data, { global: res.data.workspaceId === "GLOBAL", workspaceId: "" });
|
||||
this.temp.nodeId = this.nodeId;
|
||||
this.commandParams = this.temp.defArgs ? JSON.parse(this.temp.defArgs) : [];
|
||||
//
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.temp = { global: false, type: "add", nodeId: this.nodeId };
|
||||
}
|
||||
},
|
||||
// 提交 Script 数据
|
||||
handleEditScriptOk() {
|
||||
if (this.temp.scriptType === "server-sync") {
|
||||
this.$notification.warning({
|
||||
message: "服务端同步的脚本不能在此修改",
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!this.temp.nodeId) {
|
||||
this.$notification.warning({
|
||||
message: "没有选择节点不能保存脚本",
|
||||
});
|
||||
return;
|
||||
}
|
||||
// 检验表单
|
||||
this.$refs["editScriptForm"].validate((valid) => {
|
||||
if (!valid) {
|
||||
return false;
|
||||
}
|
||||
if (this.commandParams && this.commandParams.length > 0) {
|
||||
for (let i = 0; i < this.commandParams.length; i++) {
|
||||
if (!this.commandParams[i].desc) {
|
||||
this.$notification.error({
|
||||
message: "请填写第" + (i + 1) + "个参数的描述",
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
this.temp.defArgs = JSON.stringify(this.commandParams);
|
||||
} else {
|
||||
this.temp.defArgs = "";
|
||||
}
|
||||
// 提交数据
|
||||
editScript(this.temp).then((res) => {
|
||||
if (res.code === 200) {
|
||||
// 成功
|
||||
this.$notification.success({
|
||||
message: res.msg,
|
||||
});
|
||||
|
||||
this.$emit("close");
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="node-full-content">
|
||||
<div class="">
|
||||
<!-- 数据表格 -->
|
||||
<a-table :data-source="list" size="middle" :columns="columns" @change="changePage" :pagination="pagination" bordered rowKey="id">
|
||||
<template slot="title">
|
||||
@ -85,74 +85,16 @@
|
||||
</template>
|
||||
</a-table>
|
||||
<!-- 编辑区 -->
|
||||
<a-modal destroyOnClose v-model="editScriptVisible" title="编辑 Script" @ok="handleEditScriptOk" :maskClosable="false" width="80vw">
|
||||
<a-form-model ref="editScriptForm" :rules="rules" :model="temp" :label-col="{ span: 3 }" :wrapper-col="{ span: 19 }">
|
||||
<a-alert v-if="this.temp.scriptType === 'server-sync'" message="服务端同步的脚本不能在此修改" banner />
|
||||
<a-form-model-item label="选择节点" v-if="!temp.nodeId">
|
||||
<a-select v-model="temp.nodeId" :disabled="!!temp.nodeId" allowClear placeholder="请选择节点">
|
||||
<a-select-option v-for="(nodeName, key) in nodeMap" :key="key">{{ nodeName }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-model-item>
|
||||
<template v-if="temp.nodeId">
|
||||
<a-form-model-item label="Script 名称" prop="name">
|
||||
<a-input v-model="temp.name" placeholder="名称" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="Script 内容" prop="context">
|
||||
<div style="height: 40vh; overflow-y: scroll">
|
||||
<code-editor v-model="temp.context" :options="{ mode: 'shell', tabSize: 2, theme: 'abcdef' }"></code-editor>
|
||||
</div>
|
||||
</a-form-model-item>
|
||||
<!-- <a-form-model-item label="默认参数" prop="defArgs">
|
||||
<a-input v-model="temp.defArgs" placeholder="默认参数" />
|
||||
</a-form-model-item> -->
|
||||
<a-form-model-item label="默认参数">
|
||||
<div v-for="(item, index) in commandParams" :key="item.key">
|
||||
<a-row type="flex" justify="center" align="middle">
|
||||
<a-col :span="22">
|
||||
<a-input :addon-before="`参数${index + 1}描述`" v-model="item.desc" placeholder="参数描述,参数描述没有实际作用,仅是用于提示参数的含义" />
|
||||
<a-input :addon-before="`参数${index + 1}值`" v-model="item.value" placeholder="参数值,添加默认参数后在手动执行脚本时需要填写参数值" />
|
||||
</a-col>
|
||||
<a-col :span="2">
|
||||
<a-row type="flex" justify="center" align="middle">
|
||||
<a-col>
|
||||
<a-icon @click="() => commandParams.splice(index, 1)" type="minus-circle" style="color: #ff0000" />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-divider style="margin: 5px 0" />
|
||||
</div>
|
||||
|
||||
<a-button type="primary" @click="() => commandParams.push({})">添加参数</a-button>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="共享" prop="global">
|
||||
<a-radio-group v-model="temp.global">
|
||||
<a-radio :value="true"> 全局</a-radio>
|
||||
<a-radio :value="false"> 当前工作空间</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="定时执行" prop="autoExecCron">
|
||||
<a-auto-complete
|
||||
v-model="temp.autoExecCron"
|
||||
placeholder="如果需要定时自动执行则填写,cron 表达式.默认未开启秒级别,需要去修改配置文件中:[system.timerMatchSecond])"
|
||||
option-label-prop="value"
|
||||
>
|
||||
<template slot="dataSource">
|
||||
<a-select-opt-group v-for="group in cronDataSource" :key="group.title">
|
||||
<span slot="label">
|
||||
{{ group.title }}
|
||||
</span>
|
||||
<a-select-option v-for="opt in group.children" :key="opt.title" :value="opt.value"> {{ opt.title }} {{ opt.value }} </a-select-option>
|
||||
</a-select-opt-group>
|
||||
</template>
|
||||
</a-auto-complete>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="描述" prop="description">
|
||||
<a-input v-model="temp.description" type="textarea" :rows="3" style="resize: none" placeholder="详细描述" />
|
||||
</a-form-model-item>
|
||||
</template>
|
||||
</a-form-model>
|
||||
</a-modal>
|
||||
<ScriptEdit
|
||||
v-if="editScriptVisible"
|
||||
:nodeId="temp.nodeId"
|
||||
:scriptId="temp.scriptId"
|
||||
@close="
|
||||
() => {
|
||||
editScriptVisible = false;
|
||||
}
|
||||
"
|
||||
></ScriptEdit>
|
||||
<!-- 脚本控制台组件 -->
|
||||
<a-drawer
|
||||
:title="drawerTitle"
|
||||
@ -249,18 +191,19 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { delAllCache, deleteScript, editScript, getScriptListAll, itemScript, getTriggerUrl, unbindScript, syncScript } from "@/api/node-other";
|
||||
import codeEditor from "@/components/codeEditor";
|
||||
import { delAllCache, deleteScript, getScriptListAll, getTriggerUrl, unbindScript, syncScript } from "@/api/node-other";
|
||||
|
||||
import { getNodeListAll } from "@/api/node";
|
||||
import ScriptConsole from "@/pages/node/node-layout/other/script-console";
|
||||
import { CHANGE_PAGE, COMPUTED_PAGINATION, CRON_DATA_SOURCE, PAGE_DEFAULT_LIST_QUERY, parseTime } from "@/utils/const";
|
||||
import { CHANGE_PAGE, COMPUTED_PAGINATION, PAGE_DEFAULT_LIST_QUERY, parseTime } from "@/utils/const";
|
||||
import ScriptLog from "@/pages/node/node-layout/other/script-log";
|
||||
import ScriptEdit from "@/pages/node/script-edit";
|
||||
import Vue from "vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ScriptConsole,
|
||||
codeEditor,
|
||||
ScriptEdit,
|
||||
ScriptLog,
|
||||
},
|
||||
props: {
|
||||
@ -273,7 +216,7 @@ export default {
|
||||
return {
|
||||
loading: false,
|
||||
listQuery: Object.assign({}, PAGE_DEFAULT_LIST_QUERY),
|
||||
cronDataSource: CRON_DATA_SOURCE,
|
||||
|
||||
list: [],
|
||||
temp: {},
|
||||
nodeMap: {},
|
||||
@ -310,12 +253,8 @@ export default {
|
||||
{ title: "最后操作人", dataIndex: "lastRunUser", ellipsis: true, scopedSlots: { customRender: "lastRunUser" }, width: 120 },
|
||||
{ title: "操作", dataIndex: "operation", align: "center", scopedSlots: { customRender: "operation" }, fixed: "right", width: "240px" },
|
||||
],
|
||||
rules: {
|
||||
name: [{ required: true, message: "请输入脚本名称", trigger: "blur" }],
|
||||
context: [{ required: true, message: "请输入脚本内容", trigger: "blur" }],
|
||||
},
|
||||
|
||||
triggerVisible: false,
|
||||
commandParams: [],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@ -350,72 +289,15 @@ export default {
|
||||
});
|
||||
},
|
||||
parseTime,
|
||||
// 修改
|
||||
// 编辑
|
||||
handleEdit(record) {
|
||||
this.$refs["editScriptForm"]?.resetFields();
|
||||
if (record) {
|
||||
itemScript({
|
||||
id: record.scriptId,
|
||||
nodeId: record.nodeId,
|
||||
}).then((res) => {
|
||||
if (res.code === 200) {
|
||||
this.temp = Object.assign({}, res.data, { global: res.data.workspaceId === "GLOBAL", workspaceId: "" });
|
||||
this.temp.nodeId = record.nodeId;
|
||||
this.commandParams = this.temp.defArgs ? JSON.parse(this.temp.defArgs) : [];
|
||||
//
|
||||
this.editScriptVisible = true;
|
||||
}
|
||||
});
|
||||
this.temp = { ...record };
|
||||
} else {
|
||||
this.temp = { global: false, type: "add", nodeId: this.listQuery.nodeId };
|
||||
this.editScriptVisible = true;
|
||||
this.temp = { nodeId: this.listQuery.nodeId };
|
||||
}
|
||||
},
|
||||
// 提交 Script 数据
|
||||
handleEditScriptOk() {
|
||||
if (this.temp.scriptType === "server-sync") {
|
||||
this.$notification.warning({
|
||||
message: "服务端同步的脚本不能在此修改",
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!this.temp.nodeId) {
|
||||
this.$notification.warning({
|
||||
message: "没有选择节点不能保存脚本",
|
||||
});
|
||||
return;
|
||||
}
|
||||
// 检验表单
|
||||
this.$refs["editScriptForm"].validate((valid) => {
|
||||
if (!valid) {
|
||||
return false;
|
||||
}
|
||||
if (this.commandParams && this.commandParams.length > 0) {
|
||||
for (let i = 0; i < this.commandParams.length; i++) {
|
||||
if (!this.commandParams[i].desc) {
|
||||
this.$notification.error({
|
||||
message: "请填写第" + (i + 1) + "个参数的描述",
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
this.temp.defArgs = JSON.stringify(this.commandParams);
|
||||
} else {
|
||||
this.temp.defArgs = "";
|
||||
}
|
||||
// 提交数据
|
||||
editScript(this.temp).then((res) => {
|
||||
if (res.code === 200) {
|
||||
// 成功
|
||||
this.$notification.success({
|
||||
message: res.msg,
|
||||
});
|
||||
|
||||
this.editScriptVisible = false;
|
||||
this.loadData();
|
||||
}
|
||||
});
|
||||
});
|
||||
this.editScriptVisible = true;
|
||||
},
|
||||
handleDelete(record) {
|
||||
this.$confirm({
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="node-full-content">
|
||||
<div class="">
|
||||
<!-- 数据表格 -->
|
||||
<a-table :data-source="list" size="middle" :columns="columns" @change="changePage" :pagination="pagination" bordered rowKey="id">
|
||||
<template slot="title">
|
||||
|
@ -234,6 +234,12 @@ export const PROJECT_DSL_DEFATUL =
|
||||
"# scriptArgs: restart\r\n" +
|
||||
"# scriptEnv:\r\n" +
|
||||
'# "boot_active": test\r\n' +
|
||||
"# reload:\r\n" +
|
||||
"## scriptId: project.sh\r\n" +
|
||||
"# scriptId: \r\n" +
|
||||
"# scriptArgs: reload\r\n" +
|
||||
"# scriptEnv:\r\n" +
|
||||
'# "boot_active": test\r\n' +
|
||||
"file:\r\n" +
|
||||
"# 备份文件保留个数\r\n" +
|
||||
"# backupCount: 5\r\n" +
|
||||
|
Loading…
Reference in New Issue
Block a user