mirror of
https://gitee.com/dromara/Jpom.git
synced 2024-12-04 04:49:48 +08:00
!242 i18n: pages dispatch
Merge pull request !242 from a20070322/task/i18n
This commit is contained in:
commit
bcead8ba41
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [ 16.x ]
|
||||
node-version: [ 18.x ]
|
||||
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
@ -2,10 +2,18 @@
|
||||
|
||||
## 2.11.5.0
|
||||
|
||||
### 🐣 新增功能
|
||||
|
||||
1. 【all】新增 自由脚本方便调试机器节点
|
||||
|
||||
### 🐞 解决BUG、优化功能
|
||||
|
||||
1. 【server】修复 资产管理 SSH 配置禁用命令无法回显(感谢@zhangw)
|
||||
2. 【server】修复 资产管理 SSH 未配置授权目录时 NPE (感谢[@Anley](https://gitee.com/MrAnley) [Gitee issues I9J17G](https://gitee.com/dromara/Jpom/issues/I9J17G) )
|
||||
2. 【server】修复 资产管理 SSH 未配置授权目录时 NPE (感谢[@Anley](https://gitee.com/MrAnley) [Gitee issues I9J17G](https://gitee.com/dromara/Jpom/issues/I9J17G) )
|
||||
3. 【agent】优化 监控机器网络流程支持配置排除网卡或者仅统计对应的网卡
|
||||
4. 【server】修复 退出登录时页面会提示需要登录相关信息
|
||||
5. 【server】优化 页面检测新版本判断是否加入 beta
|
||||
6. 【agent】优化 添加数据记录修改人(感谢[@陈旭](https://gitee.com/chenxu8989) [Gitee issues I9JSY7](https://gitee.com/dromara/Jpom/issues/I9JSY7) )
|
||||
|
||||
------
|
||||
|
||||
|
@ -40,6 +40,9 @@ public class HttpTransportServer implements TransportServer {
|
||||
UrlBuilder urlBuilder = UrlBuilder.of(url).addPath(urlItem.path());
|
||||
HttpRequest httpRequest = HttpRequest.of(urlBuilder);
|
||||
httpRequest.setMethod(method);
|
||||
// 添加请求头
|
||||
Map<String, String> header = urlItem.header();
|
||||
httpRequest.headerMap(header, true);
|
||||
|
||||
Optional.ofNullable(urlItem.timeout()).ifPresent(integer -> httpRequest.timeout(integer * 1000));
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
# See the Mulan PSL v2 for more details.
|
||||
#
|
||||
|
||||
FROM maven:3.8.5-jdk-8-slim as builder
|
||||
FROM maven:3.9.6-eclipse-temurin-8 as builder
|
||||
WORKDIR /target/dependency
|
||||
COPY . .
|
||||
|
||||
|
@ -37,7 +37,7 @@ import java.util.Optional;
|
||||
@Configuration
|
||||
@ConfigurationProperties("jpom")
|
||||
@Data
|
||||
@EnableConfigurationProperties({ProjectConfig.class, ProjectLogConfig.class, SystemConfig.class, AgentAuthorize.class})
|
||||
@EnableConfigurationProperties({ProjectConfig.class, ProjectLogConfig.class, SystemConfig.class, AgentAuthorize.class, MonitorConfig.class, MonitorConfig.NetworkConfig.class})
|
||||
public class AgentConfig implements ILoadEvent, InitializingBean {
|
||||
|
||||
private final JpomApplication jpomApplication;
|
||||
@ -59,6 +59,11 @@ public class AgentConfig implements ILoadEvent, InitializingBean {
|
||||
* 系统配置参数
|
||||
*/
|
||||
private SystemConfig system;
|
||||
/**
|
||||
* 监控配置
|
||||
*/
|
||||
private MonitorConfig monitor;
|
||||
|
||||
/**
|
||||
* 数据目录
|
||||
*/
|
||||
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Of Him Code Technology Studio
|
||||
* Jpom is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
package org.dromara.jpom.configuration;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* @author bwcx_jzy
|
||||
* @since 2024/4/24
|
||||
*/
|
||||
@Data
|
||||
@ConfigurationProperties("jpom.monitor")
|
||||
public class MonitorConfig {
|
||||
|
||||
private NetworkConfig network;
|
||||
|
||||
@Data
|
||||
@ConfigurationProperties("jpom.monitor.network")
|
||||
public static class NetworkConfig {
|
||||
/**
|
||||
* 忽略的网卡,多个使用逗号分隔
|
||||
*/
|
||||
private String statExcludeNames;
|
||||
/**
|
||||
* 仅统计的网卡
|
||||
* ,多个使用逗号分隔
|
||||
*/
|
||||
private String statContainsOnlyNames;
|
||||
}
|
||||
}
|
@ -23,6 +23,8 @@ import org.dromara.jpom.common.RemoteVersion;
|
||||
import org.dromara.jpom.common.commander.ProjectCommander;
|
||||
import org.dromara.jpom.common.commander.SystemCommander;
|
||||
import org.dromara.jpom.common.interceptor.NotAuthorize;
|
||||
import org.dromara.jpom.configuration.AgentConfig;
|
||||
import org.dromara.jpom.configuration.MonitorConfig;
|
||||
import org.dromara.jpom.model.data.NodeProjectInfoModel;
|
||||
import org.dromara.jpom.model.data.NodeScriptModel;
|
||||
import org.dromara.jpom.plugin.PluginFactory;
|
||||
@ -39,6 +41,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@ -55,15 +58,18 @@ public class IndexController extends BaseAgentController {
|
||||
private final NodeScriptServer nodeScriptServer;
|
||||
private final SystemCommander systemCommander;
|
||||
private final ProjectCommander projectCommander;
|
||||
private final AgentConfig agentConfig;
|
||||
|
||||
public IndexController(ProjectInfoService projectInfoService,
|
||||
NodeScriptServer nodeScriptServer,
|
||||
SystemCommander systemCommander,
|
||||
ProjectCommander projectCommander) {
|
||||
ProjectCommander projectCommander,
|
||||
AgentConfig agentConfig) {
|
||||
this.projectInfoService = projectInfoService;
|
||||
this.nodeScriptServer = nodeScriptServer;
|
||||
this.systemCommander = systemCommander;
|
||||
this.projectCommander = projectCommander;
|
||||
this.agentConfig = agentConfig;
|
||||
}
|
||||
|
||||
@RequestMapping(value = {"index", "", "index.html", "/"}, produces = MediaType.TEXT_PLAIN_VALUE)
|
||||
@ -83,6 +89,7 @@ public class IndexController extends BaseAgentController {
|
||||
jsonObject.put("remoteVersion", remoteVersion);
|
||||
jsonObject.put("pluginSize", PluginFactory.size());
|
||||
jsonObject.put("joinBetaRelease", RemoteVersion.betaRelease());
|
||||
jsonObject.put("monitor", agentConfig.getMonitor());
|
||||
return JsonMessage.success("", jsonObject);
|
||||
}
|
||||
|
||||
@ -95,7 +102,9 @@ public class IndexController extends BaseAgentController {
|
||||
public IJsonMessage<JSONObject> getDirectTop() {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
try {
|
||||
JSONObject topInfo = org.dromara.jpom.util.OshiUtils.getSimpleInfo();
|
||||
Optional<MonitorConfig> monitorConfig = Optional.ofNullable(agentConfig).map(AgentConfig::getMonitor);
|
||||
|
||||
JSONObject topInfo = org.dromara.jpom.util.OshiUtils.getSimpleInfo(monitorConfig.orElse(null));
|
||||
jsonObject.put("simpleStatus", topInfo);
|
||||
// 系统固定休眠时间
|
||||
jsonObject.put("systemSleep", org.dromara.jpom.util.OshiUtils.NET_STAT_SLEEP + org.dromara.jpom.util.OshiUtils.CPU_STAT_SLEEP);
|
||||
|
@ -30,6 +30,7 @@ public abstract class BaseWorkspaceOptService<T extends BaseWorkspaceModel> exte
|
||||
String userName = BaseAgentController.getNowUserName();
|
||||
if (!StrUtil.DASHED.equals(userName)) {
|
||||
t.setCreateUser(userName);
|
||||
t.setModifyUser(userName);
|
||||
}
|
||||
super.addItem(t);
|
||||
}
|
||||
@ -52,6 +53,10 @@ public abstract class BaseWorkspaceOptService<T extends BaseWorkspaceModel> exte
|
||||
@Override
|
||||
public void updateById(T updateData, String id) {
|
||||
updateData.setModifyTime(DateUtil.now());
|
||||
String userName = BaseAgentController.getNowUserName();
|
||||
if (!StrUtil.DASHED.equals(userName)) {
|
||||
updateData.setModifyUser(userName);
|
||||
}
|
||||
super.updateById(updateData, id);
|
||||
}
|
||||
}
|
||||
|
@ -90,6 +90,13 @@ public class AgentFreeWebSocketScriptHandle extends BaseAgentWebSocketHandle {
|
||||
return;
|
||||
}
|
||||
JSONObject json = JSONObject.parseObject(message);
|
||||
String type = json.getString("type");
|
||||
if (StrUtil.equals(type, "close")) {
|
||||
// 关闭、停止脚本执行
|
||||
IoUtil.close(CACHE.remove(session.getId()));
|
||||
session.close();
|
||||
return;
|
||||
}
|
||||
String path = json.getString("path");
|
||||
String tag = json.getString("tag");
|
||||
JSONObject environment = json.getJSONObject("environment");
|
||||
@ -172,10 +179,12 @@ public class AgentFreeWebSocketScriptHandle extends BaseAgentWebSocketHandle {
|
||||
processBuilder.redirectErrorStream(true);
|
||||
processBuilder.command(command);
|
||||
//
|
||||
File directory = FileUtil.file(path).getAbsoluteFile();
|
||||
// 需要创建目录
|
||||
FileUtil.mkdir(directory);
|
||||
processBuilder.directory(directory);
|
||||
if (StrUtil.isNotEmpty(path)) {
|
||||
File directory = FileUtil.file(path).getAbsoluteFile();
|
||||
// 需要创建目录
|
||||
FileUtil.mkdir(directory);
|
||||
processBuilder.directory(directory);
|
||||
}
|
||||
//
|
||||
process = processBuilder.start();
|
||||
inputStream = process.getInputStream();
|
||||
|
@ -9,6 +9,7 @@
|
||||
*/
|
||||
package org.dromara.jpom.util;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.date.SystemClock;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
@ -16,6 +17,9 @@ import cn.hutool.system.oshi.CpuInfo;
|
||||
import cn.hutool.system.oshi.OshiUtil;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import lombok.Data;
|
||||
import org.dromara.jpom.configuration.MonitorConfig;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.PathMatcher;
|
||||
import oshi.hardware.*;
|
||||
import oshi.software.os.FileSystem;
|
||||
import oshi.software.os.NetworkParams;
|
||||
@ -41,6 +45,8 @@ public class OshiUtils {
|
||||
public static final int NET_STAT_SLEEP = 1000;
|
||||
public static final int CPU_STAT_SLEEP = 1000;
|
||||
|
||||
private static final PathMatcher pathMatcher = new AntPathMatcher();
|
||||
|
||||
static {
|
||||
// 解决Oshi获取CPU使用率与Windows任务管理器显示不匹配的问题
|
||||
GlobalConfig.set(GlobalConfig.OSHI_OS_WINDOWS_CPU_UTILITY, true);
|
||||
@ -97,7 +103,7 @@ public class OshiUtils {
|
||||
*
|
||||
* @return json
|
||||
*/
|
||||
public static JSONObject getSimpleInfo() {
|
||||
public static JSONObject getSimpleInfo(MonitorConfig monitorConfig) {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("time", SystemClock.now());
|
||||
CpuInfo cpuInfo = OshiUtil.getCpuInfo(CPU_STAT_SLEEP);
|
||||
@ -129,33 +135,55 @@ public class OshiUtils {
|
||||
}
|
||||
jsonObject.put("disk", NumberUtil.div(used, total, 2) * 100);
|
||||
//
|
||||
NetIoInfo startNetInfo = getNetInfo();
|
||||
|
||||
MonitorConfig.NetworkConfig networkConfig1 = Optional.ofNullable(monitorConfig)
|
||||
.map(MonitorConfig::getNetwork).orElse(null);
|
||||
NetIoInfo startNetInfo = getNetInfo(networkConfig1);
|
||||
//暂停1秒
|
||||
Util.sleep(NET_STAT_SLEEP);
|
||||
NetIoInfo endNetInfo = getNetInfo();
|
||||
NetIoInfo endNetInfo = getNetInfo(networkConfig1);
|
||||
jsonObject.put("netTxBytes", endNetInfo.getTxbyt() - startNetInfo.getTxbyt());
|
||||
jsonObject.put("netRxBytes", endNetInfo.getRxbyt() - startNetInfo.getRxbyt());
|
||||
jsonObject.put("monitorIfsNames", endNetInfo.getIfsNames());
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
private static NetIoInfo getNetInfo() {
|
||||
private static NetIoInfo getNetInfo(MonitorConfig.NetworkConfig networkConfig) {
|
||||
//
|
||||
List<String> statExcludeNames = Optional.ofNullable(networkConfig)
|
||||
.map(MonitorConfig.NetworkConfig::getStatExcludeNames)
|
||||
.map(s -> StrUtil.splitTrim(s, StrUtil.COMMA))
|
||||
.orElse(CollUtil.newArrayList());
|
||||
List<String> statContainsOnlyNames = Optional.ofNullable(networkConfig)
|
||||
.map(MonitorConfig.NetworkConfig::getStatContainsOnlyNames)
|
||||
.map(s -> StrUtil.splitTrim(s, StrUtil.COMMA))
|
||||
.orElse(CollUtil.newArrayList());
|
||||
long rxBytesBegin = 0;
|
||||
long txBytesBegin = 0;
|
||||
long rxPacketsBegin = 0;
|
||||
long txPacketsBegin = 0;
|
||||
List<NetworkIF> listBegin = OshiUtil.getNetworkIFs();
|
||||
for (NetworkIF net : listBegin) {
|
||||
rxBytesBegin += net.getBytesRecv();
|
||||
txBytesBegin += net.getBytesSent();
|
||||
rxPacketsBegin += net.getPacketsRecv();
|
||||
txPacketsBegin += net.getPacketsSent();
|
||||
StringBuilder ifsNames = new StringBuilder(StrUtil.EMPTY);
|
||||
if (listBegin != null) {
|
||||
listBegin = listBegin.stream()
|
||||
.filter(networkIF -> CollUtil.isEmpty(statExcludeNames) || !isMatch(statExcludeNames, networkIF.getName()))
|
||||
.filter(networkIF -> CollUtil.isEmpty(statContainsOnlyNames) || isMatch(statContainsOnlyNames, networkIF.getName()))
|
||||
.collect(Collectors.toList());
|
||||
for (int i = 0; i < listBegin.size(); i++) {
|
||||
NetworkIF net = listBegin.get(i);
|
||||
rxBytesBegin += net.getBytesRecv();
|
||||
txBytesBegin += net.getBytesSent();
|
||||
rxPacketsBegin += net.getPacketsRecv();
|
||||
txPacketsBegin += net.getPacketsSent();
|
||||
ifsNames.append(i == 0 ? net.getName() : "," + net.getName());
|
||||
}
|
||||
}
|
||||
NetIoInfo netIoInfo = new NetIoInfo();
|
||||
netIoInfo.setRxbyt(rxBytesBegin);
|
||||
netIoInfo.setTxbyt(txBytesBegin);
|
||||
netIoInfo.setRxpck(rxPacketsBegin);
|
||||
netIoInfo.setTxpck(txPacketsBegin);
|
||||
netIoInfo.setIfsNames(ifsNames.toString());
|
||||
return netIoInfo;
|
||||
}
|
||||
|
||||
@ -307,6 +335,15 @@ public class OshiUtils {
|
||||
.orElse(new ArrayList<>());
|
||||
}
|
||||
|
||||
public static boolean isMatch(List<String> list, String keyword) {
|
||||
for (String pattern : list) {
|
||||
if (pathMatcher.match(pattern, keyword)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Data
|
||||
private static class NetIoInfo {
|
||||
/**
|
||||
@ -328,5 +365,9 @@ public class OshiUtils {
|
||||
* 发送的KB数,txbit/s
|
||||
*/
|
||||
private Long txbyt;
|
||||
/**
|
||||
* ifaceNames
|
||||
*/
|
||||
private String ifsNames;
|
||||
}
|
||||
}
|
||||
|
@ -53,6 +53,12 @@ jpom:
|
||||
allowed-downgrade: false
|
||||
# 执行系统主要命名是否填充 sudo(sudo xxx) 使用前提需要配置 sudo 免密
|
||||
command-use-sudo: false
|
||||
monitor:
|
||||
network:
|
||||
# 监控网络流量只统计对应的网卡,多个使用逗号分隔. 支持模糊匹配
|
||||
stat-contains-only-names: en*
|
||||
# 监控网络流量排除对应的网卡,多个使用逗号分隔. 支持模糊匹配
|
||||
stat-exclude-names: lo*
|
||||
server:
|
||||
#运行端口号
|
||||
port: 2123
|
||||
|
@ -51,6 +51,12 @@ jpom:
|
||||
allowed-downgrade: false
|
||||
# 执行系统主要命名是否填充 sudo(sudo xxx) 使用前提需要配置 sudo 免密
|
||||
command-use-sudo: false
|
||||
monitor:
|
||||
network:
|
||||
# 监控网络流量只统计对应的网卡,多个使用逗号分隔
|
||||
stat-contains-only-names:
|
||||
# 监控网络流量排除对应的网卡,多个使用逗号分隔
|
||||
stat-exclude-names:
|
||||
server:
|
||||
#运行端口号
|
||||
port: 2123
|
||||
|
@ -0,0 +1,33 @@
|
||||
package org.dromara.jpom;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.system.oshi.OshiUtil;
|
||||
import org.dromara.jpom.util.OshiUtils;
|
||||
import org.junit.Test;
|
||||
import oshi.hardware.NetworkIF;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author bwcx_jzy1
|
||||
* @since 2024/4/25
|
||||
*/
|
||||
public class OshiNetworkTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
List<NetworkIF> listBegin = OshiUtil.getNetworkIFs();
|
||||
System.out.println(listBegin.size());
|
||||
List<String> statExcludeNames = CollUtil.newArrayList("lo*", "ap*");
|
||||
List<String> statContainsOnlyNames = CollUtil.newArrayList("en*");
|
||||
listBegin = listBegin.stream()
|
||||
.filter(networkIF -> CollUtil.isEmpty(statExcludeNames) || !OshiUtils.isMatch(statExcludeNames, networkIF.getName()))
|
||||
.filter(networkIF -> CollUtil.isEmpty(statContainsOnlyNames) || OshiUtils.isMatch(statContainsOnlyNames, networkIF.getName()))
|
||||
.collect(Collectors.toList());
|
||||
for (NetworkIF anIf : listBegin) {
|
||||
System.out.println(anIf.getName());
|
||||
}
|
||||
// System.out.println(listBegin);
|
||||
}
|
||||
}
|
@ -33,6 +33,10 @@ public class ApacheExecUtil {
|
||||
private static final ShutdownHookProcessDestroyer shutdownHookProcessDestroyer = new ShutdownHookProcessDestroyer();
|
||||
private static final Map<String, Process> processMap = new SafeConcurrentHashMap<>();
|
||||
|
||||
public static void addProcess(Process process) {
|
||||
shutdownHookProcessDestroyer.add(process);
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭 Process
|
||||
*
|
||||
@ -87,21 +91,25 @@ public class ApacheExecUtil {
|
||||
.get();
|
||||
//
|
||||
executor.setProcessDestroyer(new ProcessDestroyer() {
|
||||
private int size = 0;
|
||||
|
||||
@Override
|
||||
public boolean add(Process process) {
|
||||
processMap.put(execId, process);
|
||||
size++;
|
||||
return shutdownHookProcessDestroyer.add(process);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Process process) {
|
||||
processMap.remove(execId);
|
||||
size--;
|
||||
return shutdownHookProcessDestroyer.remove(process);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return shutdownHookProcessDestroyer.size();
|
||||
return size;
|
||||
}
|
||||
});
|
||||
pumpStreamHandler.stop();
|
||||
|
@ -15,6 +15,7 @@ import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.io.LineHandler;
|
||||
import cn.hutool.core.util.*;
|
||||
import cn.hutool.system.OsInfo;
|
||||
import cn.hutool.system.SystemUtil;
|
||||
import lombok.Lombok;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -45,6 +46,9 @@ public class CommandUtil {
|
||||
* 文件后缀
|
||||
*/
|
||||
public static final String SUFFIX;
|
||||
|
||||
public static final String SUFFIX_UNIX = "sh";
|
||||
public static final String SUFFIX_WINDOWS = "bat";
|
||||
/**
|
||||
* 执行前缀
|
||||
*/
|
||||
@ -59,23 +63,23 @@ public class CommandUtil {
|
||||
private static final ThreadLocal<Map<String, String>> CACHE_COMMAND_RESULT = new ThreadLocal<>();
|
||||
|
||||
static {
|
||||
if (SystemUtil.getOsInfo().isLinux()) {
|
||||
OsInfo osInfo = SystemUtil.getOsInfo();
|
||||
if (osInfo.isLinux() || osInfo.isMac() || osInfo.isMacOsX() || osInfo.isIrix() || osInfo.isHpUx()) {
|
||||
//执行linux系统命令
|
||||
COMMAND.add("/bin/bash");
|
||||
COMMAND.add("-c");
|
||||
} else if (SystemUtil.getOsInfo().isMac()) {
|
||||
COMMAND.add("/bin/bash");
|
||||
COMMAND.add("-c");
|
||||
} else {
|
||||
} else if (osInfo.isWindows()) {
|
||||
COMMAND.add("cmd");
|
||||
COMMAND.add("/c");
|
||||
} else {
|
||||
log.error("不支持的系统类型:{}", osInfo.getName());
|
||||
}
|
||||
//
|
||||
if (SystemUtil.getOsInfo().isWindows()) {
|
||||
SUFFIX = "bat";
|
||||
if (osInfo.isWindows()) {
|
||||
SUFFIX = SUFFIX_WINDOWS;
|
||||
EXECUTE_PREFIX = StrUtil.EMPTY;
|
||||
} else {
|
||||
SUFFIX = "sh";
|
||||
SUFFIX = SUFFIX_UNIX;
|
||||
EXECUTE_PREFIX = "bash";
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
# syntax = docker/dockerfile:experimental
|
||||
|
||||
FROM maven:3.8.5-jdk-8-slim as builder
|
||||
FROM maven:3.9.6-eclipse-temurin-8 as builder
|
||||
WORKDIR /target/dependency
|
||||
COPY . .
|
||||
|
||||
@ -46,7 +46,7 @@ RUN --mount=type=cache,target=/target/dependency/web-vue/node_modules cd web-vue
|
||||
|
||||
RUN --mount=type=cache,target=/root/.m2 mvn -B -e -T 1C clean package -pl modules/server -am -Dmaven.test.skip=true -Dmaven.compile.fork=true -s script/settings.xml
|
||||
|
||||
FROM maven:3.8.5-jdk-8
|
||||
FROM maven:3.9.6-eclipse-temurin-8
|
||||
|
||||
ARG BUILD_DATE
|
||||
ARG JPOM_VERSION
|
||||
|
@ -8,7 +8,7 @@
|
||||
# See the Mulan PSL v2 for more details.
|
||||
#
|
||||
|
||||
FROM maven:3.8.6-jdk-8
|
||||
FROM maven:3.9.6-eclipse-temurin-8
|
||||
|
||||
ARG BUILD_DATE
|
||||
LABEL build_info="dromara/Jpom build-date:- ${BUILD_DATE}"
|
||||
|
@ -8,7 +8,7 @@
|
||||
# See the Mulan PSL v2 for more details.
|
||||
#
|
||||
|
||||
FROM maven:3.8.5-openjdk-17-slim
|
||||
FROM maven:3.9.6-sapmachine-17
|
||||
|
||||
ARG BUILD_DATE
|
||||
LABEL build_info="dromara/Jpom build-date:- ${BUILD_DATE}"
|
||||
|
@ -8,7 +8,7 @@
|
||||
# See the Mulan PSL v2 for more details.
|
||||
#
|
||||
|
||||
FROM maven:3.8.6-jdk-8
|
||||
FROM maven:3.9.6-eclipse-temurin-8
|
||||
|
||||
ARG BUILD_DATE
|
||||
LABEL build_info="dromara/Jpom build-date:- ${BUILD_DATE}"
|
||||
|
@ -8,7 +8,7 @@
|
||||
# See the Mulan PSL v2 for more details.
|
||||
#
|
||||
|
||||
FROM maven:3.8.6-jdk-8
|
||||
FROM maven:3.9.6-sapmachine-17
|
||||
|
||||
ARG BUILD_DATE
|
||||
LABEL build_info="dromara/Jpom build-date:- ${BUILD_DATE}"
|
||||
|
@ -207,6 +207,8 @@ public class MachineDockerController extends BaseGroupNameController {
|
||||
throw new IllegalArgumentException("仓库账号或者密码错误:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
// 修改状态为在线
|
||||
dockerInfoModel.setStatus(1);
|
||||
}
|
||||
|
||||
@GetMapping(value = "try-local-docker", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ -219,7 +221,7 @@ public class MachineDockerController extends BaseGroupNameController {
|
||||
entity.set("host", dockerHost);
|
||||
boolean exists = machineDockerServer.exists(entity);
|
||||
if (exists) {
|
||||
return new JsonMessage<>(405, "已经存在本地 docker 信息啦,不要重复添加");
|
||||
return new JsonMessage<>(405, "已经存在本地 docker 信息啦,不要重复添加:" + dockerHost);
|
||||
}
|
||||
MachineDockerModel dockerModel = new MachineDockerModel();
|
||||
dockerModel.setHost(dockerHost);
|
||||
|
@ -254,4 +254,16 @@ public class MachineNodeController extends BaseGroupNameController {
|
||||
}
|
||||
return JsonMessage.success("修正成功");
|
||||
}
|
||||
|
||||
@GetMapping(value = "monitor-config", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Feature(method = MethodFeature.LIST)
|
||||
public IJsonMessage<JSONObject> info(HttpServletRequest request, String id) {
|
||||
IJsonMessage<JSONObject> message = this.tryRequestMachine(id, request, NodeUrl.Info);
|
||||
Assert.notNull(message, "没有对应的资产机器");
|
||||
Assert.state(message.success(), message.getMsg());
|
||||
//
|
||||
JSONObject data = message.getData();
|
||||
JSONObject monitor = Optional.ofNullable(data).map(jsonObject -> jsonObject.getJSONObject("monitor")).orElse(null);
|
||||
return JsonMessage.success("", monitor);
|
||||
}
|
||||
}
|
||||
|
@ -194,7 +194,10 @@ public class MachineNodeModel extends BaseGroupNameModel implements INodeInfo {
|
||||
* 安装 id
|
||||
*/
|
||||
private String installId;
|
||||
|
||||
/**
|
||||
* 扩展信息
|
||||
*/
|
||||
private String extendInfo;
|
||||
/**
|
||||
* 传输加密方式 0 不加密 1 BASE64 2 AES
|
||||
*/
|
||||
|
@ -15,7 +15,6 @@ import cn.hutool.core.comparator.CompareUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.date.SystemClock;
|
||||
import cn.hutool.core.net.NetUtil;
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
@ -300,6 +299,8 @@ public class MachineNodeServer extends BaseDbService<MachineNodeModel> implement
|
||||
MachineNodeStatLogModel machineNodeStatLogModel = new MachineNodeStatLogModel();
|
||||
machineNodeStatLogModel.setMachineId(machineNodeModel.getId());
|
||||
machineNodeStatLogModel.setNetworkDelay(networkDelay);
|
||||
//
|
||||
JSONObject extendInfo = new JSONObject();
|
||||
Optional.ofNullable(data.getJSONObject("simpleStatus")).ifPresent(jsonObject -> {
|
||||
machineNodeModel.setOsOccupyMemory(ObjectUtil.defaultIfNull(jsonObject.getDouble("memory"), -1D));
|
||||
machineNodeModel.setOsOccupyDisk(ObjectUtil.defaultIfNull(jsonObject.getDouble("disk"), -1D));
|
||||
@ -313,6 +314,8 @@ public class MachineNodeServer extends BaseDbService<MachineNodeModel> implement
|
||||
machineNodeStatLogModel.setNetTxBytes(jsonObject.getLong("netTxBytes"));
|
||||
machineNodeStatLogModel.setNetRxBytes(jsonObject.getLong("netRxBytes"));
|
||||
machineNodeStatLogModel.setMonitorTime(jsonObject.getLongValue("time"));
|
||||
//
|
||||
extendInfo.put("monitorIfsNames", jsonObject.getString("monitorIfsNames"));
|
||||
});
|
||||
// 系统信息
|
||||
Optional.ofNullable(data.getJSONObject("systemInfo")).ifPresent(jsonObject -> {
|
||||
@ -336,6 +339,7 @@ public class MachineNodeServer extends BaseDbService<MachineNodeModel> implement
|
||||
machineNodeModel.setOsLoadAverage(CollUtil.join(osLoadAverage, StrUtil.COMMA));
|
||||
machineNodeModel.setOsFileStoreTotal(jsonObject.getLong("osFileStoreTotal"));
|
||||
});
|
||||
machineNodeModel.setExtendInfo(extendInfo.toString());
|
||||
this.updateById(machineNodeModel);
|
||||
if (machineNodeStatLogModel.getMonitorTime() != null) {
|
||||
machineNodeStatLogServer.insert(machineNodeStatLogModel);
|
||||
|
@ -117,6 +117,7 @@ public enum ClassFeature {
|
||||
NODE_SCRIPT("节点脚本模板", ClassFeature.NODE, NodeScriptServer.class),
|
||||
NODE_SCRIPT_LOG("节点脚本模板日志", ClassFeature.NODE, NodeScriptExecuteLogServer.class),
|
||||
AGENT_LOG("插件端系统日志", ClassFeature.NODE),
|
||||
FREE_SCRIPT("自由脚本", ClassFeature.NODE, MachineNodeServer.class),
|
||||
// TOMCAT_FILE("Tomcat file", ClassFeature.NODE),
|
||||
// TOMCAT_LOG("Tomcat log", ClassFeature.NODE),
|
||||
|
||||
|
@ -92,7 +92,7 @@ public abstract class BaseProxyHandler extends BaseHandler {
|
||||
IUrlItem urlItem = NodeForward.parseUrlItem(nodeInfo, workspaceId, this.nodeUrl, DataContentType.FORM_URLENCODED);
|
||||
|
||||
IProxyWebSocket proxySession = TransportServerFactory.get().websocket(nodeInfo, urlItem, parameters);
|
||||
proxySession.onMessage(s -> sendMsg(session, s));
|
||||
proxySession.onMessage(s -> onProxyMessage(session, s));
|
||||
if (!proxySession.connectBlocking()) {
|
||||
this.sendMsg(session, "插件端连接失败");
|
||||
this.destroy(session);
|
||||
@ -104,6 +104,10 @@ public abstract class BaseProxyHandler extends BaseHandler {
|
||||
attributes.put("init", true);
|
||||
}
|
||||
|
||||
protected void onProxyMessage(WebSocketSession session, String msg) {
|
||||
sendMsg(session, msg);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
|
||||
@ -115,7 +119,7 @@ public abstract class BaseProxyHandler extends BaseHandler {
|
||||
ConsoleCommandOp consoleCommandOp = StrUtil.isNotEmpty(op) ? ConsoleCommandOp.valueOf(op) : null;
|
||||
String textMessage;
|
||||
if (proxySession != null) {
|
||||
textMessage = this.handleTextMessage(attributes, proxySession, json, consoleCommandOp);
|
||||
textMessage = this.handleTextMessage(attributes, session, proxySession, json, consoleCommandOp);
|
||||
} else {
|
||||
textMessage = this.handleTextMessage(attributes, session, json, consoleCommandOp);
|
||||
}
|
||||
@ -139,6 +143,22 @@ public abstract class BaseProxyHandler extends BaseHandler {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息处理方法
|
||||
*
|
||||
* @param attributes 属性
|
||||
* @param proxySession 代理回话
|
||||
* @param json 数据
|
||||
* @param consoleCommandOp 操作类型
|
||||
*/
|
||||
protected String handleTextMessage(Map<String, Object> attributes,
|
||||
WebSocketSession session,
|
||||
IProxyWebSocket proxySession,
|
||||
JSONObject json,
|
||||
ConsoleCommandOp consoleCommandOp) throws IOException {
|
||||
return this.handleTextMessage(attributes, proxySession, json, consoleCommandOp);
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息处理方法
|
||||
*
|
||||
|
@ -63,6 +63,7 @@ public enum HandlerType {
|
||||
* 容器 终端
|
||||
*/
|
||||
docker(DockerCliHandler.class, DockerInfoService.class, MachineDockerServer.class, "machineDockerId"),
|
||||
freeScript(FreeScriptHandler.class, null),
|
||||
;
|
||||
final Class<?> handlerClass;
|
||||
|
||||
|
@ -71,5 +71,8 @@ public class ServerWebSocketConfig implements WebSocketConfigurer {
|
||||
// docker cli
|
||||
registry.addHandler(new DockerCliHandler(), "/socket/docker_cli")
|
||||
.addInterceptors(serverWebSocketInterceptor).setAllowedOrigins("*");
|
||||
// free script
|
||||
registry.addHandler(new FreeScriptHandler(), "/socket/free_script")
|
||||
.addInterceptors(serverWebSocketInterceptor).setAllowedOrigins("*");
|
||||
}
|
||||
}
|
||||
|
@ -178,6 +178,13 @@ public class ServerWebSocketInterceptor implements HandshakeInterceptor {
|
||||
break;
|
||||
case nodeUpdate:
|
||||
break;
|
||||
case freeScript:
|
||||
//
|
||||
MachineNodeModel machine = (MachineNodeModel) attributes.get("machine");
|
||||
if (machine == null) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -0,0 +1,90 @@
|
||||
package org.dromara.jpom.socket.handler;
|
||||
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.jpom.common.forward.NodeUrl;
|
||||
import org.dromara.jpom.func.assets.model.MachineNodeModel;
|
||||
import org.dromara.jpom.permission.ClassFeature;
|
||||
import org.dromara.jpom.permission.Feature;
|
||||
import org.dromara.jpom.permission.MethodFeature;
|
||||
import org.dromara.jpom.socket.BaseProxyHandler;
|
||||
import org.dromara.jpom.socket.ConsoleCommandOp;
|
||||
import org.dromara.jpom.system.ExtConfigBean;
|
||||
import org.dromara.jpom.transport.IProxyWebSocket;
|
||||
import org.dromara.jpom.util.CommandUtil;
|
||||
import org.dromara.jpom.util.SocketSessionUtil;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author bwcx_jzy1
|
||||
* @since 2024/4/26
|
||||
*/
|
||||
@Feature(cls = ClassFeature.FREE_SCRIPT, method = MethodFeature.EXECUTE)
|
||||
@Slf4j
|
||||
public class FreeScriptHandler extends BaseProxyHandler {
|
||||
|
||||
public FreeScriptHandler() {
|
||||
super(NodeUrl.FreeScriptRun);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object[] getParameters(Map<String, Object> attributes) {
|
||||
return new Object[]{};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String handleTextMessage(Map<String, Object> attributes, WebSocketSession session, IProxyWebSocket proxySession, JSONObject json, ConsoleCommandOp consoleCommandOp) throws IOException {
|
||||
|
||||
String content = json.getString("content");
|
||||
if (StrUtil.isEmpty(content)) {
|
||||
SocketSessionUtil.send(session, "没有需要执行的内容");
|
||||
session.close();
|
||||
return null;
|
||||
}
|
||||
|
||||
MachineNodeModel machine = (MachineNodeModel) attributes.get("machine");
|
||||
String osName = machine.getOsName();
|
||||
String template = StrUtil.EMPTY;
|
||||
boolean appendTemplate = json.getBooleanValue("appendTemplate");
|
||||
if (appendTemplate && StrUtil.isNotEmpty(osName)) {
|
||||
InputStream templateInputStream;
|
||||
if (osName.startsWith("Windows")) {
|
||||
templateInputStream = ExtConfigBean.getConfigResourceInputStream("/exec/template." + CommandUtil.SUFFIX_WINDOWS);
|
||||
} else {
|
||||
templateInputStream = ExtConfigBean.getConfigResourceInputStream("/exec/template." + CommandUtil.SUFFIX_UNIX);
|
||||
}
|
||||
template = IoUtil.readUtf8(templateInputStream);
|
||||
}
|
||||
|
||||
String uuid = IdUtil.fastSimpleUUID();
|
||||
json.put("tag", uuid);
|
||||
json.put("content", template + content);
|
||||
String path = json.getString("path");
|
||||
json.put("path", StrUtil.emptyToDefault(path, "./"));
|
||||
json.put("environment", new JSONObject());
|
||||
attributes.put("uuidTag", uuid);
|
||||
proxySession.send(json.toString());
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProxyMessage(WebSocketSession session, String msg) {
|
||||
if (StrUtil.equals(msg, "JPOM_SYSTEM_TAG:" + session.getAttributes().get("uuidTag"))) {
|
||||
// 执行结束
|
||||
try {
|
||||
session.close();
|
||||
} catch (IOException e) {
|
||||
log.error("关闭客户端回话异常", e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
super.onProxyMessage(session, msg);
|
||||
}
|
||||
}
|
@ -87,7 +87,6 @@ public class InitDb implements DisposableBean, ILoadEvent {
|
||||
AFTER_CALLBACK.put(name, supplier);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void afterPropertiesSet(ApplicationContext applicationContext) {
|
||||
this.prepareCallback(applicationContext.getEnvironment());
|
||||
//
|
||||
|
@ -15,3 +15,4 @@ ALTER,STATIC_FILE_STORAGE,absolutePath,String,300,,文件路径,false
|
||||
ALTER,STATIC_FILE_STORAGE,name,String,100,,文件名,false
|
||||
ADD,TRIGGER_TOKEN_LOG,triggerCount,Integer,,,触发次数
|
||||
ADD,USER_INFO,source,String,100,,账号来源
|
||||
ADD,MACHINE_NODE_INFO,extendInfo,TEXT,,,扩展信息
|
||||
|
|
@ -18,7 +18,11 @@
|
||||
# docker buildx create --use
|
||||
|
||||
# 服务端
|
||||
docker buildx build --platform linux/amd64,linux/arm64 -t jpomdocker/jpom:2.11.5.1 -t jpomdocker/jpom:latest -f ./modules/server/DockerfileRelease --push .
|
||||
docker buildx build --platform linux/amd64,linux/arm64,linux/ppc64le,linux/arm64/v8 -t jpomdocker/jpom:2.11.5.1 -t jpomdocker/jpom:latest -f ./modules/server/DockerfileRelease --push .
|
||||
|
||||
|
||||
|
||||
docker buildx build --platform linux/amd64,linux/arm64,linux/ppc64le,linux/arm64/v8 -t jpomdocker/jpom:2-test -f ./modules/server/DockerfileBeta --push .
|
||||
#
|
||||
#docker buildx build --platform linux/amd64,linux/arm64 -t jpomdocker/jpom:latest -f ./modules/server/DockerfileRelease --push .
|
||||
|
||||
|
@ -7,4 +7,3 @@
|
||||
/// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
/// See the Mulan PSL v2 for more details.
|
||||
///
|
||||
|
||||
|
@ -116,3 +116,11 @@ export function machineCorrectLonelyData(data) {
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function machineMonitorConfig(data) {
|
||||
return axios({
|
||||
url: '/system/assets/machine/monitor-config',
|
||||
method: 'get',
|
||||
params: data
|
||||
})
|
||||
}
|
||||
|
@ -1,5 +1,11 @@
|
||||
<template>
|
||||
<div :style="`margin-top:${marginTop}`">
|
||||
<div
|
||||
:style="{
|
||||
marginTop: marginTop,
|
||||
minHeight: height,
|
||||
height: height
|
||||
}"
|
||||
>
|
||||
<div class="log-filter">
|
||||
<a-row type="flex" align="middle">
|
||||
<a-col>
|
||||
@ -27,7 +33,7 @@
|
||||
</a-row>
|
||||
</div>
|
||||
<!-- <pre class="log-view" :id="`${this.id}`" :style="`height:${this.height}`">{{ defText }}</pre> -->
|
||||
<viewPre ref="viewPre" :height="height" :config="temp"></viewPre>
|
||||
<viewPre ref="viewPre" :height="`calc(${height} - 35px - 20px)`" :config="temp"></viewPre>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -219,7 +219,7 @@ export default {
|
||||
// res.data.
|
||||
this.showVersion(false, res.data?.remoteVersion).then((upgrade) => {
|
||||
// 本地网络检测
|
||||
this.loaclCheckVersion(!upgrade)
|
||||
this.localCheckVersion(!upgrade)
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -412,19 +412,23 @@ export default {
|
||||
this.showVersion(true, res.data).then((upgrade) => {
|
||||
// 远程检测失败才本地检测
|
||||
if (!upgrade) {
|
||||
this.loaclCheckVersion(true)
|
||||
this.localCheckVersion(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
// 本地网络检测
|
||||
loaclCheckVersion(tip) {
|
||||
localCheckVersion(tip) {
|
||||
//console.log(compareVersion("1.0.0", "1.0.1"), compareVersion("2.4.3", "2.4.2"));
|
||||
//console.log(compareVersion("1.0.2", "dev"));
|
||||
const buildInfo = pageBuildInfo()
|
||||
|
||||
executionRequest('https://jpom.top/docs/release-versions.json', {
|
||||
const url = this.temp?.joinBetaRelease
|
||||
? 'https://jpom.top/docs/beta-versions.json'
|
||||
: 'https://jpom.top/docs/release-versions.json'
|
||||
|
||||
executionRequest(url, {
|
||||
...buildInfo,
|
||||
type: this.nodeId || this.machineId ? 'agent' : 'server'
|
||||
}).then((data) => {
|
||||
|
10
web-vue/src/d.ts/auto-global-import.d.ts
vendored
10
web-vue/src/d.ts/auto-global-import.d.ts
vendored
@ -1,13 +1,3 @@
|
||||
///
|
||||
/// Copyright (c) 2019 Of Him Code Technology Studio
|
||||
/// Jpom is licensed under Mulan PSL v2.
|
||||
/// You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
/// You may obtain a copy of Mulan PSL v2 at:
|
||||
/// http://license.coscl.org.cn/MulanPSL2
|
||||
/// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
/// See the Mulan PSL v2 for more details.
|
||||
///
|
||||
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
// @ts-nocheck
|
||||
|
10
web-vue/src/d.ts/auto-import.d.ts
vendored
10
web-vue/src/d.ts/auto-import.d.ts
vendored
@ -1,13 +1,3 @@
|
||||
///
|
||||
/// Copyright (c) 2019 Of Him Code Technology Studio
|
||||
/// Jpom is licensed under Mulan PSL v2.
|
||||
/// You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
/// You may obtain a copy of Mulan PSL v2 at:
|
||||
/// http://license.coscl.org.cn/MulanPSL2
|
||||
/// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
/// See the Mulan PSL v2 for more details.
|
||||
///
|
||||
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
// @ts-nocheck
|
||||
|
10
web-vue/src/d.ts/components.d.ts
vendored
10
web-vue/src/d.ts/components.d.ts
vendored
@ -1,13 +1,3 @@
|
||||
///
|
||||
/// Copyright (c) 2019 Of Him Code Technology Studio
|
||||
/// Jpom is licensed under Mulan PSL v2.
|
||||
/// You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
/// You may obtain a copy of Mulan PSL v2 at:
|
||||
/// http://license.coscl.org.cn/MulanPSL2
|
||||
/// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
/// See the Mulan PSL v2 for more details.
|
||||
///
|
||||
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
// @ts-nocheck
|
||||
|
@ -11,10 +11,12 @@
|
||||
import page404 from './pages/404/404'
|
||||
import build from './pages/build'
|
||||
import certificate from './pages/certificate'
|
||||
import dispatch from './pages/dispatch'
|
||||
export default {
|
||||
pages: {
|
||||
404: page404,
|
||||
build,
|
||||
certificate
|
||||
certificate,
|
||||
dispatch
|
||||
}
|
||||
}
|
||||
|
17
web-vue/src/i18n/locales/en_US/pages/dispatch/index.ts
Normal file
17
web-vue/src/i18n/locales/en_US/pages/dispatch/index.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import log from './log'
|
||||
import logRead from './logRead'
|
||||
import start from './start'
|
||||
import status from './status'
|
||||
import whiteList from './white-list'
|
||||
import list from './list'
|
||||
import logReadView from './logReadView'
|
||||
|
||||
export default {
|
||||
logReadView,
|
||||
log,
|
||||
logRead,
|
||||
start,
|
||||
status,
|
||||
whiteList,
|
||||
list
|
||||
}
|
189
web-vue/src/i18n/locales/en_US/pages/dispatch/list.ts
Normal file
189
web-vue/src/i18n/locales/en_US/pages/dispatch/list.ts
Normal file
@ -0,0 +1,189 @@
|
||||
export default {
|
||||
c: {
|
||||
distributionType: 'Distribution Type',
|
||||
independent: 'Independent',
|
||||
related: 'Related',
|
||||
unknown: 'Unknown',
|
||||
yes: 'Yes',
|
||||
no: 'No',
|
||||
edit: 'Edit',
|
||||
distributionID: 'Distribution ID',
|
||||
distributionIDEqualsProjectID: 'Distribution ID equals Project ID',
|
||||
cannotModifyAfterCreation: 'Cannot modify after creation',
|
||||
randomlyGenerated: 'Randomly generated',
|
||||
distributionName: 'Distribution Name',
|
||||
groupingName: 'Grouping Name:',
|
||||
addNewGrouping: 'Add New Grouping',
|
||||
selectGrouping: 'Select Grouping',
|
||||
distributionNode: 'Distribution Node',
|
||||
noProjectInThisNode: 'No project in this node',
|
||||
independentDistribution: '[Independent Distribution]',
|
||||
distributionOperationAfter: 'Operation after distribution',
|
||||
selectOperationAfterPublish: 'Select operation after publish',
|
||||
intervalTime: 'Interval Time',
|
||||
ensureProjectRestart:
|
||||
'Ensure project restart when using sequential restart, full sequential restart during multi-node distribution',
|
||||
waitPreviousProjectStart: 'Wait for the previous project to start before closing the next project',
|
||||
configureBasedOnProjectStartTime: 'Please configure based on your project start time',
|
||||
suggestedIntervalTime: 'It is generally recommended to be more than 10 seconds',
|
||||
distributionIntervalTimeEffect:
|
||||
'Distribution interval time (sequential restart, full sequential restart) is effective',
|
||||
secondaryDirectory: 'Secondary Directory',
|
||||
publishToRootIfNotFilled: 'Publish to the root of the project if not filled',
|
||||
clearPublish: 'Clear Publish',
|
||||
clearPublishDescription:
|
||||
'Clear publish means that before uploading new files, all files in the project folder directory will be deleted first, and then the new files will be saved',
|
||||
publishStopBefore:
|
||||
'Stop before publishing means that when publishing files to the project file, the project will be closed first, and then the file replacement will be carried out. This avoids the situation where files are occupied in the Windows environment',
|
||||
publishStopBeforeColon: 'Stop before publishing:',
|
||||
distributionRequestAddress:
|
||||
'Distribution process request corresponding address, start distribution, distribution completed, distribution failed, cancel distribution',
|
||||
parametersForDistribution: 'Parameters entered: outGivingId, outGivingName, status, statusMsg, executeTime',
|
||||
statusValues: 'Values: 1',
|
||||
distributionStatuses: 'Distribution in progress, 2: Distribution ended, 3: Canceled, 4: Distribution failed',
|
||||
asynchronousRequest: 'Asynchronous requests cannot guarantee order',
|
||||
distributionProcessRequest: 'Distribution process request, optional, GET request',
|
||||
immutableAfterCreation: 'Immutable after creation, Distribution ID equals Project ID',
|
||||
runProject: 'Run Project',
|
||||
selectProjectAuthorizationPath: 'Select Project Authorization Path',
|
||||
configuration: 'Configuration',
|
||||
configurationExample: 'Configuration Example',
|
||||
defaultLogDirectory: 'Default is in the plugin data directory /${projectId}/${projectId}.log',
|
||||
selectProject: 'Select Project',
|
||||
systemPrompt: 'System Prompt',
|
||||
confirm: 'Confirm',
|
||||
cancel: 'Cancel'
|
||||
},
|
||||
p: {
|
||||
distributionID: 'Distribution ID',
|
||||
name: 'Name',
|
||||
selectGrouping: 'Select Grouping',
|
||||
selectStatus: 'Select Status',
|
||||
quickBackToFirstPage: 'Hold Ctr or Alt/Option and click the button to quickly return to the first page',
|
||||
search: 'Search',
|
||||
addRelated: 'Add Related',
|
||||
addDistribution: 'Add Distribution',
|
||||
nodeDistributionDescription:
|
||||
'Node distribution refers to a project that needs to run on multiple nodes (servers). Use node distribution to manage this project uniformly (distributed project management functionality can be achieved)',
|
||||
addRelatedProjectDescription:
|
||||
'Adding a related project means associating a project that has already been created in the node as a node distribution project for unified management',
|
||||
createDistributionProjectDescription:
|
||||
'Creating a distribution project means creating a new project that belongs to the node distribution. After creation, the project information will be automatically synchronized to the corresponding node. Changes to the node distribution information will also be automatically synchronized to the corresponding node',
|
||||
distributionFiles: 'Distribution Files',
|
||||
more: 'More',
|
||||
cancelDistribution: 'Cancel Distribution',
|
||||
delete: 'Delete',
|
||||
release: 'Release',
|
||||
deleteCompletely: 'Delete Completely',
|
||||
unbind: 'Unbind',
|
||||
editRelatedProject: 'Edit Related Project',
|
||||
addRelatedProject: 'Add Related Project',
|
||||
noData: 'No data, please add node project data first',
|
||||
node: 'Node:',
|
||||
selectNode: 'Select Node',
|
||||
noNodeInfo: 'No node information',
|
||||
project: 'Project:',
|
||||
add: 'Add',
|
||||
editDistributionProject: 'Edit Distribution Project',
|
||||
createDistributionProject: 'Create Distribution Project',
|
||||
loadingData: 'Loading Data',
|
||||
remind: 'Remind',
|
||||
noLogicalNode: 'There is no logical node in the current workspace, and node distribution cannot be created',
|
||||
distributionName: 'Distribution Name (Project Name)',
|
||||
runningMode: 'Running Mode',
|
||||
scriptTemplate: 'Custom project management with script template',
|
||||
staticFolder: 'Project is a static folder',
|
||||
noProjectStatus: 'No project status and control functions',
|
||||
selectRunningMode: 'Select Running Mode',
|
||||
notRecommended: 'Not Recommended',
|
||||
projectPath: 'Project Path',
|
||||
authorizationPath: 'Authorization path refers to the folder where the project files are stored in the service',
|
||||
modifyAuthorizationConfig: 'You can modify it in [Node Distribution] => [Distribution Authorization Configuration]',
|
||||
projectFolder: 'Project Folder is the actual directory name where the project is stored',
|
||||
projectFilesStored: 'Project files will be stored in',
|
||||
authorizationPathProjectFolder: 'Authorization Path + Project Folder',
|
||||
jarFolder: 'The folder where the project is stored, the folder where the jar package is stored',
|
||||
configureAuthorizationDirectory: 'You need to configure the authorization directory in advance for the workspace',
|
||||
configureDirectory: 'Configure Directory',
|
||||
projectFullDirectory: 'Project Full Directory',
|
||||
content: 'Content',
|
||||
yamlConfig:
|
||||
'Configure in yaml/yml format, scriptId is the relative path of the script file under the project path or the server-side script template ID, which can be viewed in the server-side script template editing dialog box',
|
||||
variablesInScript: 'Variables supported in the script include: ${PROJECT_ID}, ${PROJECT_NAME}, ${PROJECT_PATH}',
|
||||
scriptOutput: 'After the process is executed, the script must output: running',
|
||||
processID: 'The actual process ID of the current project',
|
||||
incorrectOutputFormat:
|
||||
'If the last line of the output is not the expected format, the project status will be unrun',
|
||||
referToConfigExample: 'For configuration details, please refer to the configuration example',
|
||||
recommendedScriptDistribution: 'It is recommended to use the server-side script distribution to the script:',
|
||||
viewServerScript: 'View Server Script',
|
||||
fillProjectDSLConfig:
|
||||
'Please fill in the project DSL configuration content, you can click the tab above to view the configuration example',
|
||||
logDirectory: 'Log Directory',
|
||||
logDirectorySelection: 'Log Directory refers to the console log storage directory',
|
||||
sameConfigAsAuthorizationDirectory:
|
||||
'The list of options is consistent with the project authorization directory, that is, the same configuration',
|
||||
selectLogDirectory: 'Select Log Directory',
|
||||
mainClass: 'The main class for program execution (can be left blank for jar mode)',
|
||||
jvmArgs: 'Fill in [xxx',
|
||||
jvmArgsExample: '-Dext.dirs=xxx: -cp xx : xx]',
|
||||
selectDistributionNode: 'Select Distribution Node',
|
||||
jvmParams: 'JVM Parameters',
|
||||
params: 'Parameters',
|
||||
nonMandatory: 'Not Mandatory',
|
||||
jvmParamsExample: 'jvm, e.g.: -Xms512m -Xmx512m',
|
||||
argsParams: 'Args Parameters',
|
||||
functionArgsParams: 'Function args parameters, not mandatory',
|
||||
argsParamsExample: 'e.g.: --server',
|
||||
autoStart: 'Auto Start',
|
||||
checkProjectStatus:
|
||||
'Check project status when the plugin starts, if the project status is unrun, try to start the project',
|
||||
nonServerAutoStart: 'Non-server auto-start, if you need auto-start at boot, it is recommended to configure',
|
||||
pluginAutoStart: 'Plugin side auto-start at boot',
|
||||
turnOnAutoStart: 'And turn on this switch',
|
||||
on: 'On',
|
||||
off: 'Off',
|
||||
pluginAutoCheckProjectOnStart:
|
||||
'Automatically check the project when the plugin starts, if not started, it will attempt to start',
|
||||
dslEnvironmentVariables: 'DSL environment variables',
|
||||
environmentVariables: 'Environment variables',
|
||||
exampleVariable: 'For example: key1',
|
||||
projectRequestOnStartStopRestart:
|
||||
'When the project starts, stops, or restarts, it will request the corresponding address',
|
||||
parametersForProjectRequest: 'The input parameters are: projectId, projectName, type, result',
|
||||
valuesForProjectRequest: 'The values are: stop, beforeStop, start, beforeRestart',
|
||||
projectRequestOnFileChange:
|
||||
'When the project starts, stops, restarts, or a file changes, it will request the corresponding address, optional, GET request',
|
||||
configureAuthorizationDirectory1: 'Configure the authorization directory',
|
||||
viewScript: 'View script',
|
||||
projectGrouping: 'Project grouping',
|
||||
distributionStatus: 'After distribution',
|
||||
status: 'Status',
|
||||
creationTime: 'Creation time',
|
||||
modificationTime: 'Modification time',
|
||||
modifiedBy: 'Modified by',
|
||||
operations: 'Operations',
|
||||
enterProjectID: 'Please enter the project ID',
|
||||
enterProjectName: 'Please enter the project name',
|
||||
selectProjectRunningMode: 'Please select the project running mode',
|
||||
enterProjectFolder: 'Please enter the project folder',
|
||||
selectAtLeastOneNodeProject: 'Select at least 1 node project',
|
||||
selectAtLeastOneNode: 'Please select at least 1 node',
|
||||
confirmDeletionOfDistributionInfo:
|
||||
'Are you sure you want to permanently delete the distribution information? After deletion, the projects under the nodes will also be permanently deleted, and the project will automatically delete the related files (including project logs, log backups, project files)',
|
||||
confirmDeletionOfDistributionInfoSimple:
|
||||
'Are you sure you want to delete the distribution information? After deletion, the projects under the nodes will also be deleted',
|
||||
confirmReleaseOfDistributionInfo:
|
||||
'Are you sure you want to release the distribution information? After releasing, the project information under the nodes will still be retained, and if you need to delete the project, you will still need to operate in node management',
|
||||
confirmUnbindingCurrentNodeDistribution: 'Are you sure you want to unbind the current node distribution?',
|
||||
unbindCheckDataAssociation:
|
||||
'Unbinding will check data association and will not actually request the node to delete project information',
|
||||
unbindForUnreachableServer:
|
||||
'Generally used when the server cannot be connected and it has been determined not to be used anymore',
|
||||
cautionDueToMistakeOperation: 'Mistakes in operation can result in redundant data!!!',
|
||||
dangerousOperation: 'Dangerous operation!!!',
|
||||
noMoreNodeProjects: 'No more node projects available, please create a project first',
|
||||
selectNodeFirst: 'Please select a node first',
|
||||
confirmCancellationOfCurrentDistribution: 'Are you sure you want to cancel the current distribution?'
|
||||
}
|
||||
}
|
29
web-vue/src/i18n/locales/en_US/pages/dispatch/log.ts
Normal file
29
web-vue/src/i18n/locales/en_US/pages/dispatch/log.ts
Normal file
@ -0,0 +1,29 @@
|
||||
export default {
|
||||
c: {
|
||||
unknown: 'Unknown',
|
||||
result: 'Distribution result'
|
||||
},
|
||||
p: {
|
||||
noLogs: 'No distribution logs available',
|
||||
selectNode: 'Please select a node',
|
||||
distributeProject: 'Distribute project',
|
||||
selectStatus: 'Please select a status',
|
||||
goToFirstPage: 'Hold Ctrl or Alt/Option key and click the button to quickly go to the first page',
|
||||
search: 'Search',
|
||||
relatedData: 'Related data:',
|
||||
details: 'Details',
|
||||
info: 'Detailed information',
|
||||
projectId: 'Distribution project ID',
|
||||
nodeName: 'Node name',
|
||||
distributeId: 'Project ID',
|
||||
method: 'Distribution method',
|
||||
duration: 'Distribution duration',
|
||||
fileSize: 'File size',
|
||||
startTime: 'Start time',
|
||||
endTime: 'End time',
|
||||
statusMessage: 'Distribution status message',
|
||||
operator: 'Operator',
|
||||
status: 'Status',
|
||||
action: 'Action'
|
||||
}
|
||||
}
|
32
web-vue/src/i18n/locales/en_US/pages/dispatch/logRead.ts
Normal file
32
web-vue/src/i18n/locales/en_US/pages/dispatch/logRead.ts
Normal file
@ -0,0 +1,32 @@
|
||||
export default {
|
||||
c: {
|
||||
logName: 'Log Name',
|
||||
action: 'Add'
|
||||
},
|
||||
p: {
|
||||
clickButtonToGoBackToFirstPage:
|
||||
'Click the button while holding Ctrl or Alt/Option to quickly go back to the first page',
|
||||
search: 'Search',
|
||||
edit: 'Edit',
|
||||
view: 'View',
|
||||
delete: 'Delete',
|
||||
editLogSearch: 'Edit Log Search',
|
||||
logItemName: 'Log Item Name',
|
||||
bindNode: 'Bind Node',
|
||||
node: 'Node:',
|
||||
pleaseSelectNode: 'Please select a node',
|
||||
project: 'Project:',
|
||||
pleaseSelectProject: 'Please select a project',
|
||||
searchAndView: 'Search and View',
|
||||
name: 'Name',
|
||||
modifier: 'Modifier',
|
||||
modificationTime: 'Modification Time',
|
||||
operation: 'Operation',
|
||||
pleaseFillInLogItemName: 'Please enter a log item name',
|
||||
atLeastSelectOneNodeAndProject: 'Please select at least one node and project',
|
||||
systemPrompt: 'System Prompt',
|
||||
reallyDeleteLogSearch: 'Are you sure you want to delete the log search?',
|
||||
confirm: 'Confirm',
|
||||
cancel: 'Cancel'
|
||||
}
|
||||
}
|
46
web-vue/src/i18n/locales/en_US/pages/dispatch/logReadView.ts
Normal file
46
web-vue/src/i18n/locales/en_US/pages/dispatch/logReadView.ts
Normal file
@ -0,0 +1,46 @@
|
||||
export default {
|
||||
c: {},
|
||||
p: {
|
||||
node: 'Node',
|
||||
chooseNode: 'Please select a node',
|
||||
searchKeyword: 'Search keyword',
|
||||
keywordHighlight:
|
||||
'Keyword highlight, supports regex (using regex may affect performance, please use it appropriately)',
|
||||
keywordRegex: 'Keyword, supports regex',
|
||||
showFirstNLines: 'Show first N lines',
|
||||
showLastNLines: 'Show last N lines',
|
||||
regexReference: 'Regex syntax reference',
|
||||
matchLinesWithNumbers: 'Match lines containing numbers',
|
||||
matchLinesWithAorB: 'Match lines containing a or b',
|
||||
exception: 'Exception',
|
||||
matchLinesWithException: 'Match lines containing exceptions',
|
||||
syntaxReference: 'Syntax reference',
|
||||
searchMode: 'Search mode',
|
||||
searchModeDescription:
|
||||
'Search mode. By default, it views the last N lines of the file. Searching from the start means searching from the specified line downwards. Searching from the end means searching upwards from the end of the file for N lines.',
|
||||
searchFromEnd: 'Search from the end',
|
||||
searchFromStart: 'Search from the start',
|
||||
firstNFileLines: 'First N lines of the file',
|
||||
lastNFileLines: 'Last N lines of the file',
|
||||
searchConfigReference: 'Search configuration reference',
|
||||
searchFromEndExample1: 'Search from the end, first 0 lines of the file, last 3 lines of the file',
|
||||
searchLastNLines: 'Search within the last 3 lines of the file',
|
||||
searchFromStartExample1: 'Search from the start, first 0 lines of the file, last 3 lines of the file',
|
||||
searchLineRange1: 'Search within lines 3 - 2147483647 of the file',
|
||||
searchFromEndExample2: 'Search from the end, first 2 lines of the file, last 3 lines of the file',
|
||||
searchLineRange2: 'Search within lines 1 - 2 of the file',
|
||||
searchFromEndExample3: 'Search from the end, first 100 lines of the file, last 100 lines of the file',
|
||||
searchLineRange3: 'Search within lines 1 - 100 of the file',
|
||||
searchFromStartExample2: 'Search from the start, first 2 lines of the file, last 3 lines of the file',
|
||||
searchLineRange4: 'Search within lines 2 - 2 of the file',
|
||||
searchFromEndExample4: 'Search from the end, first 20 lines of the file, last 3 lines of the file',
|
||||
searchLineRange5: 'Search within lines 17 - 20 of the file',
|
||||
searchFromStartExample3: 'Search from the start, first 20 lines of the file, last 3 lines of the file',
|
||||
searchLineRange6: 'Search within lines 3 - 20 of the file',
|
||||
searchReference: 'Search reference',
|
||||
error: 'Error',
|
||||
checkWsProxy: 'Please check if the ws proxy is enabled',
|
||||
sessionClosed: 'The session has been closed',
|
||||
fileNotReadable: 'The current file is not readable. You need to configure readable file authorization.'
|
||||
}
|
||||
}
|
47
web-vue/src/i18n/locales/en_US/pages/dispatch/start.ts
Normal file
47
web-vue/src/i18n/locales/en_US/pages/dispatch/start.ts
Normal file
@ -0,0 +1,47 @@
|
||||
export default {
|
||||
c: {
|
||||
selectFile: 'Select File',
|
||||
selectBuild: 'Select Build',
|
||||
selectProduct: 'Select Product',
|
||||
yes: 'Yes',
|
||||
no: 'No',
|
||||
selectPostPublishAction: 'Select Post-Publish Action',
|
||||
cancel: 'Cancel',
|
||||
confirm: 'Confirm'
|
||||
},
|
||||
p: {
|
||||
distributeProject: 'Distribute Project -',
|
||||
method: 'Method',
|
||||
buildProduct: 'Build Product',
|
||||
fileCenter: 'File Center',
|
||||
staticFile: 'Static File',
|
||||
uploadFile: 'Upload File',
|
||||
remoteDownload: 'Remote Download',
|
||||
selectDistributeFile: 'Select Distribute File',
|
||||
usedTime: 'Used Time',
|
||||
remoteDownloadURL: 'Remote Download URL',
|
||||
remoteDownloadAddress: 'Remote Download Address',
|
||||
clearPublish: 'Clear Publish',
|
||||
clearPublishDescription:
|
||||
'Clearing publish means deleting all files in the project folder directory before uploading new files and saving them.',
|
||||
unZip: 'Unzip',
|
||||
autoUnZip: 'Whether to automatically unzip uploaded compressed files. Supported compression types include tar.',
|
||||
excludeFolder: 'Exclude Folder',
|
||||
excludeFolderDescription: 'Automatically exclude extra folder names inside the compressed file when unzipping.',
|
||||
postPublishAction: 'Post-Publish Action',
|
||||
subDirectory: 'Sub-Directory',
|
||||
subDirectoryDescription: 'If not filled in, it will be published to the root directory of the project.',
|
||||
filterProject: 'Filter Project',
|
||||
filterProjectDescription:
|
||||
'After filtering, only the filtered items will be published for this operation, and it will only be effective for this operation.',
|
||||
selectPublishProject: 'Please select a project to publish.',
|
||||
selectBuildProduct: 'Select Build Product',
|
||||
selectStaticFile: 'Select Static File',
|
||||
pleaseInputRemoteAddress: 'Please enter the remote address',
|
||||
pleaseSelectFile: 'Please select a file',
|
||||
pleaseFillRemoteURL: 'Please fill in the remote URL',
|
||||
pleaseFillBuildAndProduct: 'Please fill in Build and Product',
|
||||
pleaseSelectFileCenterFile: 'Please select a file from the File Center',
|
||||
pleaseSelectStaticFileFile: 'Please select a file from the Static File'
|
||||
}
|
||||
}
|
51
web-vue/src/i18n/locales/en_US/pages/dispatch/status.ts
Normal file
51
web-vue/src/i18n/locales/en_US/pages/dispatch/status.ts
Normal file
@ -0,0 +1,51 @@
|
||||
export default {
|
||||
c: {
|
||||
status: 'Status',
|
||||
unknown: 'Unknown',
|
||||
console: 'Console'
|
||||
},
|
||||
p: {
|
||||
view: 'View',
|
||||
currentStatus: 'Current Status:',
|
||||
statusDescription: 'Status Description:',
|
||||
refresh: 'Refresh',
|
||||
seconds: 's seconds',
|
||||
refreshCountdown: 'Refresh Countdown',
|
||||
currentProjectDisabled: 'Current Project is Disabled',
|
||||
running: 'Running',
|
||||
notRunning: 'Not Running',
|
||||
processId: 'Process ID:',
|
||||
portNumber: 'Port Number:',
|
||||
file: 'File',
|
||||
configuration: 'Configuration',
|
||||
nodeName: 'Node Name:',
|
||||
projectName: 'Project Name:',
|
||||
enable: 'Enable',
|
||||
disable: 'Disable',
|
||||
unbind: 'Unbind',
|
||||
longPressToDragAndSort: 'Long press to drag and sort',
|
||||
save: 'Save',
|
||||
nodeNameLabel: 'Node Name',
|
||||
projectNameLabel: 'Project Name',
|
||||
projectStatusLabel: 'Project Status',
|
||||
processPortLabel: 'Process/Port',
|
||||
distributionStatusLabel: 'Distribution Status',
|
||||
distributionResultLabel: 'Distribution Result',
|
||||
distributionStatusMessageLabel: 'Distribution Status Message',
|
||||
distributionDurationLabel: 'Distribution Duration',
|
||||
fileSizeLabel: 'File Size',
|
||||
lastDistributionTimeLabel: 'Last Distribution Time',
|
||||
operationLabel: 'Operation',
|
||||
networkError: 'Network Error',
|
||||
fileManagement: 'File Management',
|
||||
trackFile: 'Track File',
|
||||
reallyReleaseCurrentProject: 'Are you sure you want to release (delete) the current project?',
|
||||
willNotActuallyRequestNodeToDeleteProjectInfo: 'Will not actually request the node to delete project information',
|
||||
generallyUsedWhenServerCannotBeConnectedAndIsNoLongerNeeded:
|
||||
'Generally used when the server cannot be connected and is no longer needed',
|
||||
willProduceRedundantDataIfMisoperated: 'If misoperated, redundant data will be produced!!!',
|
||||
dangerousOperation: 'Dangerous operation!!!',
|
||||
confirm: 'Confirm',
|
||||
cancel: 'Cancel'
|
||||
}
|
||||
}
|
23
web-vue/src/i18n/locales/en_US/pages/dispatch/white-list.ts
Normal file
23
web-vue/src/i18n/locales/en_US/pages/dispatch/white-list.ts
Normal file
@ -0,0 +1,23 @@
|
||||
export default {
|
||||
c: {},
|
||||
p: {
|
||||
warmReminder: 'Warm reminder',
|
||||
distributionAuthorizationPathConfig: 'Current distribution authorization path configuration for the node',
|
||||
absolutePathRequired: 'The path requires an absolute path configuration',
|
||||
authorizationPath: 'Authorization path',
|
||||
usageForCreatingDistributionProjects:
|
||||
'Used for creating node distribution projects and publishing files in the file center',
|
||||
inputAuthorizationPath:
|
||||
"Please enter the authorization path. Pressing Enter supports entering multiple paths. The system will automatically filter out '../' paths and does not allow entering the root path",
|
||||
staticDirectory: 'Static directory',
|
||||
usageForStaticFileBindingAndReading:
|
||||
'Used for static file binding and reading (it is not recommended to configure large directories to avoid scanning and consuming too many resources)',
|
||||
inputStaticPaths:
|
||||
"Please enter the static paths. Pressing Enter supports entering multiple paths. The system will automatically filter out '../' paths and does not allow entering the root path",
|
||||
remoteDownloadSecureHost: 'Remote download secure HOST',
|
||||
usageForDownloadingRemoteFiles: 'Used for downloading remote files for node distribution and file upload',
|
||||
inputRemoteDownloadSecureHosts:
|
||||
'Please enter the remote download secure HOST. Pressing Enter supports entering multiple paths. Example: https',
|
||||
submit: 'Submit'
|
||||
}
|
||||
}
|
@ -11,10 +11,12 @@
|
||||
import page404 from './pages/404/404'
|
||||
import build from './pages/build'
|
||||
import certificate from './pages/certificate'
|
||||
import dispatch from './pages/dispatch'
|
||||
export default {
|
||||
pages: {
|
||||
404: page404,
|
||||
build,
|
||||
certificate
|
||||
certificate,
|
||||
dispatch
|
||||
}
|
||||
}
|
||||
|
17
web-vue/src/i18n/locales/zh-CN/pages/dispatch/index.ts
Normal file
17
web-vue/src/i18n/locales/zh-CN/pages/dispatch/index.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import log from './log'
|
||||
import logRead from './logRead'
|
||||
import start from './start'
|
||||
import status from './status'
|
||||
import whiteList from './white-list'
|
||||
import list from './list'
|
||||
import logReadView from './logReadView'
|
||||
|
||||
export default {
|
||||
logReadView,
|
||||
log,
|
||||
logRead,
|
||||
start,
|
||||
status,
|
||||
whiteList,
|
||||
list
|
||||
}
|
174
web-vue/src/i18n/locales/zh-CN/pages/dispatch/list.ts
Normal file
174
web-vue/src/i18n/locales/zh-CN/pages/dispatch/list.ts
Normal file
@ -0,0 +1,174 @@
|
||||
export default {
|
||||
c: {
|
||||
distributionType: '分发类型',
|
||||
independent: '独立',
|
||||
related: '关联',
|
||||
unknown: '未知',
|
||||
yes: '是',
|
||||
no: '否',
|
||||
edit: '编辑',
|
||||
distributionID: '分发 ID',
|
||||
distributionIDEqualsProjectID: '分发 ID 等同于项目 ID',
|
||||
cannotModifyAfterCreation: '创建之后不能修改',
|
||||
randomlyGenerated: '随机生成',
|
||||
distributionName: '分发名称',
|
||||
groupingName: '分组名称:',
|
||||
addNewGrouping: '新增分组',
|
||||
selectGrouping: '选择分组',
|
||||
distributionNode: '分发节点',
|
||||
noProjectInThisNode: '此节点暂无项目',
|
||||
independentDistribution: '【独立分发】',
|
||||
distributionOperationAfter: '分发后操作',
|
||||
selectOperationAfterPublish: '请选择发布后操作',
|
||||
intervalTime: '间隔时间',
|
||||
ensureProjectRestart: '在执行多节点分发时候使用 顺序重启、完整顺序重启 时候需要保证项目能正常重启',
|
||||
waitPreviousProjectStart: '并等待上一个项目启动完成才能关闭下一个项目',
|
||||
configureBasedOnProjectStartTime: '请根据自身项目启动时间来配置',
|
||||
suggestedIntervalTime: '一般建议 10 秒以上',
|
||||
distributionIntervalTimeEffect: '分发间隔时间 (顺序重启、完整顺序重启)方式才生效',
|
||||
secondaryDirectory: '二级目录',
|
||||
publishToRootIfNotFilled: '不填写则发布至项目的根目录',
|
||||
clearPublish: '清空发布',
|
||||
clearPublishDescription: '清空发布是指在上传新文件前,会将项目文件夹目录里面的所有文件先删除后再保存新文件',
|
||||
publishStopBefore:
|
||||
'发布前停止是指在发布文件到项目文件时先将项目关闭,再进行文件替换。避免 windows 环境下出现文件被占用的情况',
|
||||
publishStopBeforeColon: '发布前停止:',
|
||||
distributionRequestAddress: '分发过程请求对应的地址,开始分发,分发完成,分发失败,取消分发',
|
||||
parametersForDistribution: '传入参数有:outGivingId、outGivingName、status、statusMsg、executeTime',
|
||||
statusValues: '的值有:1',
|
||||
distributionStatuses: '分发中、2:分发结束、3:已取消、4:分发失败',
|
||||
asynchronousRequest: '异步请求不能保证有序性',
|
||||
distributionProcessRequest: '分发过程请求,非必填,GET请求',
|
||||
immutableAfterCreation: '创建之后不能修改,分发 ID 等同于项目 ID',
|
||||
runProject: '运行项目',
|
||||
selectProjectAuthorizationPath: '请选择项目授权路径',
|
||||
configuration: '配置',
|
||||
configurationExample: '配置示例',
|
||||
defaultLogDirectory: '默认是在插件端数据目录/${projectId}/${projectId}.log',
|
||||
selectProject: '请选择项目',
|
||||
systemPrompt: '系统提示',
|
||||
confirm: '确认',
|
||||
cancel: '取消'
|
||||
},
|
||||
p: {
|
||||
distributionID: '分发id',
|
||||
name: '名称',
|
||||
selectGrouping: '请选择分组',
|
||||
selectStatus: '请选择状态',
|
||||
quickBackToFirstPage: '按住 Ctr 或者 Alt/Option 键点击按钮快速回到第一页',
|
||||
search: '搜索',
|
||||
addRelated: '新增关联',
|
||||
addDistribution: '新增分发',
|
||||
nodeDistributionDescription:
|
||||
'节点分发是指,一个项目运行需要在多个节点(服务器)中运行,使用节点分发来统一管理这个项目(可以实现分布式项目管理功能)',
|
||||
addRelatedProjectDescription: '新增关联项目是指,将已经在节点中创建好的项目关联为节点分发项目来实现统一管理',
|
||||
createDistributionProjectDescription:
|
||||
'创建分发项目是指,全新创建一个属于节点分发到项目,创建成功后项目信息将自动同步到对应的节点中,修改节点分发信息也自动同步到对应的节点中',
|
||||
distributionFiles: '分发文件',
|
||||
more: '更多',
|
||||
cancelDistribution: '取消分发',
|
||||
delete: '删除',
|
||||
release: '释放',
|
||||
deleteCompletely: '彻底删除',
|
||||
unbind: '解绑',
|
||||
editRelatedProject: '编辑关联项目',
|
||||
addRelatedProject: '新增关联项目',
|
||||
noData: '暂无数据,请先新增节点项目数据',
|
||||
node: '节点:',
|
||||
selectNode: '请选择节点',
|
||||
noNodeInfo: '暂无节点信息',
|
||||
project: '项目:',
|
||||
add: '新增',
|
||||
editDistributionProject: '编辑分发项目',
|
||||
createDistributionProject: '创建分发项目',
|
||||
loadingData: '加载数据中',
|
||||
remind: '提醒',
|
||||
noLogicalNode: '当前工作空间还没有逻辑节点不能创建节点分发奥',
|
||||
distributionName: '分发名称(项目名称)',
|
||||
runningMode: '运行方式',
|
||||
scriptTemplate: '配合脚本模版实现自定义项目管理',
|
||||
staticFolder: '项目为静态文件夹',
|
||||
noProjectStatus: '没有项目状态以及控制等功能',
|
||||
selectRunningMode: '请选择运行方式',
|
||||
notRecommended: '不推荐',
|
||||
projectPath: '项目路径',
|
||||
authorizationPath: '授权路径是指项目文件存放到服务中的文件夹',
|
||||
modifyAuthorizationConfig: '可以到【节点分发】=>【分发授权配置】修改',
|
||||
projectFolder: '项目文件夹是项目实际存放的目录名称',
|
||||
projectFilesStored: '项目文件会存放到',
|
||||
authorizationPathProjectFolder: '项目授权路径+项目文件夹',
|
||||
jarFolder: '项目存储的文件夹,jar 包存放的文件夹',
|
||||
configureAuthorizationDirectory: '需要提前为工作空间配置授权目录',
|
||||
configureDirectory: '配置目录',
|
||||
projectFullDirectory: '项目完整目录',
|
||||
content: '内容',
|
||||
yamlConfig:
|
||||
'以 yaml/yml 格式配置,scriptId 为项目路径下的脚本文件的相对路径或者服务端脚本模版ID,可以到服务端脚本模版编辑弹窗中查看 scriptId',
|
||||
variablesInScript: '脚本里面支持的变量有:${PROJECT_ID}、${PROJECT_NAME}、${PROJECT_PATH}',
|
||||
scriptOutput: '流程执行完脚本后,输出的内容最后一行必须为:running',
|
||||
processID: '为当前项目实际的进程ID',
|
||||
incorrectOutputFormat: '。如果输出最后一行不是预期格式项目状态将是未运行',
|
||||
referToConfigExample: '配置详情请参考配置示例',
|
||||
recommendedScriptDistribution: '建议使用服务端脚本分发到脚本:',
|
||||
viewServerScript: '查看服务端脚本',
|
||||
fillProjectDSLConfig: '请填写项目 DSL 配置内容,可以点击上方切换 tab 查看配置示例',
|
||||
logDirectory: '日志目录',
|
||||
logDirectorySelection: '日志目录是指控制台日志存储目录',
|
||||
sameConfigAsAuthorizationDirectory: '可选择的列表和项目授权目录是一致的,即相同配置',
|
||||
selectLogDirectory: '请选择日志目录',
|
||||
mainClass: '程序运行的 main 类(jar 模式运行可以不填)',
|
||||
jvmArgs: '填写【xxx',
|
||||
jvmArgsExample: '-Dext.dirs=xxx: -cp xx :xx】',
|
||||
selectDistributionNode: '请选择分发节点',
|
||||
jvmParams: 'JVM 参数',
|
||||
params: '参数',
|
||||
nonMandatory: '非必填',
|
||||
jvmParamsExample: 'jvm,.如:-Xms512m -Xmx512m',
|
||||
argsParams: 'args 参数',
|
||||
functionArgsParams: '函数 args 参数,非必填',
|
||||
argsParamsExample: '如:--server',
|
||||
autoStart: '自启动',
|
||||
checkProjectStatus: '插件端启动的时候检查项目状态,如果项目状态是未运行则尝试执行启动项目',
|
||||
nonServerAutoStart: '非服务器开机自启,如需开机自启建议配置',
|
||||
pluginAutoStart: '插件端开机自启',
|
||||
turnOnAutoStart: '并开启此开关',
|
||||
on: '开',
|
||||
off: '关',
|
||||
pluginAutoCheckProjectOnStart: '插件端启动时自动检查项目如未启动将尝试启动',
|
||||
dslEnvironmentVariables: 'DSL环境变量',
|
||||
environmentVariables: '环境变量',
|
||||
exampleVariable: '如:key1',
|
||||
projectRequestOnStartStopRestart: '项目启动,停止,重启都将请求对应的地址',
|
||||
parametersForProjectRequest: '传入参数有:projectId、projectName、type、result',
|
||||
valuesForProjectRequest: '的值有:stop、beforeStop、start、beforeRestart',
|
||||
projectRequestOnFileChange: '项目启动,停止,重启,文件变动都将请求对应的地址,非必填,GET请求',
|
||||
configureAuthorizationDirectory1: '配置授权目录',
|
||||
viewScript: '查看脚本',
|
||||
projectGrouping: '项目分组',
|
||||
distributionStatus: '分发后',
|
||||
status: '状态',
|
||||
creationTime: '创建时间',
|
||||
modificationTime: '修改时间',
|
||||
modifiedBy: '修改人',
|
||||
operations: '操作',
|
||||
enterProjectID: '请输入项目ID',
|
||||
enterProjectName: '请输入项目名称',
|
||||
selectProjectRunningMode: '请选择项目运行方式',
|
||||
enterProjectFolder: '请输入项目文件夹',
|
||||
selectAtLeastOneNodeProject: '至少选择1个节点项目',
|
||||
selectAtLeastOneNode: '请至少选择 1 个节点',
|
||||
confirmDeletionOfDistributionInfo:
|
||||
'真的要彻底删除分发信息么?删除后节点下面的项目也都将彻底删除,彻底项目会自动删除项目相关文件奥(包含项目日志,日志备份,项目文件)',
|
||||
confirmDeletionOfDistributionInfoSimple: '真的要删除分发信息么?删除后节点下面的项目也都将删除',
|
||||
confirmReleaseOfDistributionInfo:
|
||||
'真的要释放分发信息么?释放之后节点下面的项目信息还会保留,如需删除项目还需要到节点管理中操作',
|
||||
confirmUnbindingCurrentNodeDistribution: '真的要解绑当前节点分发么?',
|
||||
unbindCheckDataAssociation: '解绑会检查数据关联性,不会真实请求节点删除项目信息',
|
||||
unbindForUnreachableServer: '一般用于服务器无法连接且已经确定不再使用',
|
||||
cautionDueToMistakeOperation: '如果误操作会产生冗余数据!!!',
|
||||
dangerousOperation: '危险操作!!!',
|
||||
noMoreNodeProjects: '已无更多节点项目,请先创建项目',
|
||||
selectNodeFirst: '请先选择节点',
|
||||
confirmCancellationOfCurrentDistribution: '真的取消当前分发吗?'
|
||||
}
|
||||
}
|
29
web-vue/src/i18n/locales/zh-CN/pages/dispatch/log.ts
Normal file
29
web-vue/src/i18n/locales/zh-CN/pages/dispatch/log.ts
Normal file
@ -0,0 +1,29 @@
|
||||
export default {
|
||||
c: {
|
||||
unknown: '未知',
|
||||
result: '分发结果'
|
||||
},
|
||||
p: {
|
||||
noLogs: '没有任何分发日志',
|
||||
selectNode: '请选择节点',
|
||||
distributeProject: '分发项目',
|
||||
selectStatus: '请选择状态',
|
||||
goToFirstPage: '按住 Ctr 或者 Alt/Option 键点击按钮快速回到第一页',
|
||||
search: '搜索',
|
||||
relatedData: '关联数据:',
|
||||
details: '详情',
|
||||
info: '详情信息',
|
||||
projectId: '分发项目 ID',
|
||||
nodeName: '节点名称',
|
||||
distributeId: '项目 ID',
|
||||
method: '分发方式',
|
||||
duration: '分发耗时',
|
||||
fileSize: '文件大小',
|
||||
startTime: '开始时间',
|
||||
endTime: '结束时间',
|
||||
statusMessage: '分发状态消息',
|
||||
operator: '操作人',
|
||||
status: '状态',
|
||||
action: '操作'
|
||||
}
|
||||
}
|
31
web-vue/src/i18n/locales/zh-CN/pages/dispatch/logRead.ts
Normal file
31
web-vue/src/i18n/locales/zh-CN/pages/dispatch/logRead.ts
Normal file
@ -0,0 +1,31 @@
|
||||
export default {
|
||||
c: {
|
||||
logName: '日志名称',
|
||||
action: '新增'
|
||||
},
|
||||
p: {
|
||||
clickButtonToGoBackToFirstPage: '按住 Ctr 或者 Alt/Option 键点击按钮快速回到第一页',
|
||||
search: '搜索',
|
||||
edit: '编辑',
|
||||
view: '查看',
|
||||
delete: '删除',
|
||||
editLogSearch: '编辑日志搜索',
|
||||
logItemName: '日志项目名称',
|
||||
bindNode: '绑定节点',
|
||||
node: '节点:',
|
||||
pleaseSelectNode: '请选择节点',
|
||||
project: '项目:',
|
||||
pleaseSelectProject: '请选择项目',
|
||||
searchAndView: '搜索查看',
|
||||
name: '名称',
|
||||
modifier: '修改人',
|
||||
modificationTime: '修改时间',
|
||||
operation: '操作',
|
||||
pleaseFillInLogItemName: '请填写日志项目名称',
|
||||
atLeastSelectOneNodeAndProject: '至少选择一个节点和项目',
|
||||
systemPrompt: '系统提示',
|
||||
reallyDeleteLogSearch: '真的要删除日志搜索么?',
|
||||
confirm: '确认',
|
||||
cancel: '取消'
|
||||
}
|
||||
}
|
45
web-vue/src/i18n/locales/zh-CN/pages/dispatch/logReadView.ts
Normal file
45
web-vue/src/i18n/locales/zh-CN/pages/dispatch/logReadView.ts
Normal file
@ -0,0 +1,45 @@
|
||||
export default {
|
||||
c: {},
|
||||
p: {
|
||||
node: '节点',
|
||||
chooseNode: '请选择节点',
|
||||
searchKeyword: '搜关键词',
|
||||
keywordHighlight: '关键词高亮,支持正则(正则可能影响性能请酌情使用)',
|
||||
keywordRegex: '关键词,支持正则',
|
||||
showFirstNLines: '显示前N行',
|
||||
showLastNLines: '显示后N行',
|
||||
regexReference: '正则语法参考',
|
||||
matchLinesWithNumbers: '匹配包含数字的行',
|
||||
matchLinesWithAorB: '匹配包含 a 或者 b 的行',
|
||||
exception: '异常',
|
||||
matchLinesWithException: '匹配包含 异常 的行',
|
||||
syntaxReference: '语法参考',
|
||||
searchMode: '搜索模式',
|
||||
searchModeDescription:
|
||||
'搜索模式,默认查看文件最后多少行,从头搜索指从指定行往下搜索,从尾搜索指从文件尾往上搜索多少行',
|
||||
searchFromEnd: '从尾搜索',
|
||||
searchFromStart: '从头搜索',
|
||||
firstNFileLines: '文件前N行',
|
||||
lastNFileLines: '文件后N行',
|
||||
searchConfigReference: '搜索配置参考',
|
||||
searchFromEndExample1: '从尾搜索、文件前0行、文件后3行',
|
||||
searchLastNLines: '在文件最后 3 行中搜索',
|
||||
searchFromStartExample1: '从头搜索、文件前0行、文件后3行',
|
||||
searchLineRange1: '在文件第 3 - 2147483647 行中搜索',
|
||||
searchFromEndExample2: '从尾搜索、文件前2行、文件后3行',
|
||||
searchLineRange2: '在文件第 1 - 2 行中搜索',
|
||||
searchFromEndExample3: '从尾搜索、文件前100行、文件后100行',
|
||||
searchLineRange3: '在文件第 1 - 100 行中搜索',
|
||||
searchFromStartExample2: '从头搜索、文件前2行、文件后3行',
|
||||
searchLineRange4: '在文件第 2 - 2 行中搜索',
|
||||
searchFromEndExample4: '从尾搜索、文件前20行、文件后3行',
|
||||
searchLineRange5: '在文件第 17 - 20 行中搜索',
|
||||
searchFromStartExample3: '从头搜索、文件前20行、文件后3行',
|
||||
searchLineRange6: '在文件第 3 - 20 行中搜索',
|
||||
searchReference: '搜索参考',
|
||||
error: '错误',
|
||||
checkWsProxy: '请检查是否开启 ws 代理',
|
||||
sessionClosed: '会话已经关闭',
|
||||
fileNotReadable: '当前文件不可读,需要配置可读文件授权'
|
||||
}
|
||||
}
|
45
web-vue/src/i18n/locales/zh-CN/pages/dispatch/start.ts
Normal file
45
web-vue/src/i18n/locales/zh-CN/pages/dispatch/start.ts
Normal file
@ -0,0 +1,45 @@
|
||||
export default {
|
||||
c: {
|
||||
selectFile: '选择文件',
|
||||
selectBuild: '选择构建',
|
||||
selectProduct: '选择产物',
|
||||
yes: '是',
|
||||
no: '否',
|
||||
selectPostPublishAction: '请选择发布后操作',
|
||||
cancel: '取消',
|
||||
confirm: '确认'
|
||||
},
|
||||
p: {
|
||||
distributeProject: '分发项目-',
|
||||
method: '方式',
|
||||
buildProduct: '构建产物',
|
||||
fileCenter: '文件中心',
|
||||
staticFile: '静态文件',
|
||||
uploadFile: '上传文件',
|
||||
remoteDownload: '远程下载',
|
||||
selectDistributeFile: '选择分发文件',
|
||||
usedTime: '用时',
|
||||
remoteDownloadURL: '远程下载URL',
|
||||
remoteDownloadAddress: '远程下载地址',
|
||||
clearPublish: '清空发布',
|
||||
clearPublishDescription: '清空发布是指在上传新文件前,会将项目文件夹目录里面的所有文件先删除后再保存新文件',
|
||||
unZip: '是否解压',
|
||||
autoUnZip: '如果上传的压缩文件是否自动解压 支持的压缩包类型有 tar',
|
||||
excludeFolder: '剔除文件夹',
|
||||
excludeFolderDescription: '解压时候自动剔除压缩包里面多余的文件夹名',
|
||||
postPublishAction: '分发后操作',
|
||||
subDirectory: '二级目录',
|
||||
subDirectoryDescription: '不填写则发布至项目的根目录',
|
||||
filterProject: '筛选项目',
|
||||
filterProjectDescription: '筛选之后本次发布操作只发布筛选项,并且只对本次操作生效',
|
||||
selectPublishProject: '请选择指定发布的项目',
|
||||
selectBuildProduct: '选择构建产物',
|
||||
selectStaticFile: '选择静态文件',
|
||||
pleaseInputRemoteAddress: '请输入远程地址',
|
||||
pleaseSelectFile: '请选择文件',
|
||||
pleaseFillRemoteURL: '请填写远程URL',
|
||||
pleaseFillBuildAndProduct: '请填写构建和产物',
|
||||
pleaseSelectFileCenterFile: '请选择文件中心的文件',
|
||||
pleaseSelectStaticFileFile: '请选择静态文件中的文件'
|
||||
}
|
||||
}
|
50
web-vue/src/i18n/locales/zh-CN/pages/dispatch/status.ts
Normal file
50
web-vue/src/i18n/locales/zh-CN/pages/dispatch/status.ts
Normal file
@ -0,0 +1,50 @@
|
||||
export default {
|
||||
c: {
|
||||
status: '状态',
|
||||
unknown: '未知',
|
||||
console: '控制台'
|
||||
},
|
||||
p: {
|
||||
view: '查看',
|
||||
currentStatus: '当前状态:',
|
||||
statusDescription: '状态描述:',
|
||||
refresh: '刷新',
|
||||
seconds: 's 秒',
|
||||
refreshCountdown: '刷新倒计时',
|
||||
currentProjectDisabled: '当前项目被禁用',
|
||||
running: '运行中',
|
||||
notRunning: '未运行',
|
||||
processId: '进程号:',
|
||||
portNumber: '端口号:',
|
||||
file: '文件',
|
||||
configuration: '配置',
|
||||
nodeName: '节点名:',
|
||||
projectName: '项目名:',
|
||||
enable: '启用',
|
||||
disable: '禁用',
|
||||
unbind: '解绑',
|
||||
longPressToDragAndSort: '长按可以拖动排序',
|
||||
save: '保存',
|
||||
nodeNameLabel: '节点名称',
|
||||
projectNameLabel: '项目名称',
|
||||
projectStatusLabel: '项目状态',
|
||||
processPortLabel: '进程/端口',
|
||||
distributionStatusLabel: '分发状态',
|
||||
distributionResultLabel: '分发结果',
|
||||
distributionStatusMessageLabel: '分发状态消息',
|
||||
distributionDurationLabel: '分发耗时',
|
||||
fileSizeLabel: '文件大小',
|
||||
lastDistributionTimeLabel: '最后分发时间',
|
||||
operationLabel: '操作',
|
||||
networkError: '网络异常',
|
||||
fileManagement: '文件管理',
|
||||
trackFile: '跟踪文件',
|
||||
reallyReleaseCurrentProject: '真的要释放(删除)当前项目么?',
|
||||
willNotActuallyRequestNodeToDeleteProjectInfo: '不会真实请求节点删除项目信息',
|
||||
generallyUsedWhenServerCannotBeConnectedAndIsNoLongerNeeded: '一般用于服务器无法连接且已经确定不再使用',
|
||||
willProduceRedundantDataIfMisoperated: '如果误操作会产生冗余数据!!!',
|
||||
dangerousOperation: '危险操作!!!',
|
||||
confirm: '确认',
|
||||
cancel: '取消'
|
||||
}
|
||||
}
|
18
web-vue/src/i18n/locales/zh-CN/pages/dispatch/white-list.ts
Normal file
18
web-vue/src/i18n/locales/zh-CN/pages/dispatch/white-list.ts
Normal file
@ -0,0 +1,18 @@
|
||||
export default {
|
||||
c: {},
|
||||
p: {
|
||||
warmReminder: '温馨提醒',
|
||||
distributionAuthorizationPathConfig: '当前为节点分发的授权路径配置',
|
||||
absolutePathRequired: '路径需要配置绝对路径',
|
||||
authorizationPath: '授权路径',
|
||||
usageForCreatingDistributionProjects: '用于创建节点分发项目、文件中心发布文件',
|
||||
inputAuthorizationPath: '请输入授权路径,回车支持输入多个路径,系统会自动过滤 ../ 路径、不允许输入根路径',
|
||||
staticDirectory: '静态目录',
|
||||
usageForStaticFileBindingAndReading: '用于静态文件绑定和读取(不建议配置大目录,避免扫描消耗过多资源)',
|
||||
inputStaticPaths: '请输入静态,回车支持输入多个路径,系统会自动过滤 ../ 路径、不允许输入根路径',
|
||||
remoteDownloadSecureHost: '远程下载安全HOST',
|
||||
usageForDownloadingRemoteFiles: '用于下载远程文件来进行节点分发和文件上传',
|
||||
inputRemoteDownloadSecureHosts: '请输入远程下载安全HOST,回车支持输入多个路径,示例 https',
|
||||
submit: '提交'
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,7 @@
|
||||
:auto-refresh-time="30"
|
||||
:active-page="activePage"
|
||||
table-name="dispatch-log-list"
|
||||
empty-description="没有任何分发日志"
|
||||
:empty-description="$tl('p.noLogs')"
|
||||
size="middle"
|
||||
:data-source="list"
|
||||
:columns="columns"
|
||||
@ -21,20 +21,35 @@
|
||||
>
|
||||
<template #title>
|
||||
<a-space wrap class="search-box">
|
||||
<a-select v-model:value="listQuery.nodeId" allow-clear placeholder="请选择节点" class="search-input-item">
|
||||
<a-select
|
||||
v-model:value="listQuery.nodeId"
|
||||
allow-clear
|
||||
:placeholder="$tl('p.selectNode')"
|
||||
class="search-input-item"
|
||||
>
|
||||
<a-select-option v-for="node in nodeList" :key="node.id">{{ node.name }}</a-select-option>
|
||||
</a-select>
|
||||
<a-select v-model:value="listQuery.outGivingId" allow-clear placeholder="分发项目" class="search-input-item">
|
||||
<a-select
|
||||
v-model:value="listQuery.outGivingId"
|
||||
allow-clear
|
||||
:placeholder="$tl('p.distributeProject')"
|
||||
class="search-input-item"
|
||||
>
|
||||
<a-select-option v-for="dispatch in dispatchList" :key="dispatch.id">{{ dispatch.name }}</a-select-option>
|
||||
</a-select>
|
||||
<a-select v-model:value="listQuery.status" allow-clear placeholder="请选择状态" class="search-input-item">
|
||||
<a-select
|
||||
v-model:value="listQuery.status"
|
||||
allow-clear
|
||||
:placeholder="$tl('p.selectStatus')"
|
||||
class="search-input-item"
|
||||
>
|
||||
<a-select-option v-for="(item, key) in dispatchStatusMap" :key="key" :value="key">{{
|
||||
item
|
||||
}}</a-select-option>
|
||||
</a-select>
|
||||
<a-range-picker :show-time="{ format: 'HH:mm:ss' }" format="YYYY-MM-DD HH:mm:ss" @change="onchangeTime" />
|
||||
<a-tooltip title="按住 Ctr 或者 Alt/Option 键点击按钮快速回到第一页">
|
||||
<a-button :loading="loading" type="primary" @click="loadData">搜索</a-button>
|
||||
<a-tooltip :title="$tl('p.goToFirstPage')">
|
||||
<a-button :loading="loading" type="primary" @click="loadData">{{ $tl('p.search') }}</a-button>
|
||||
</a-tooltip>
|
||||
</a-space>
|
||||
</template>
|
||||
@ -67,7 +82,10 @@
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'mode'">
|
||||
<a-tooltip placement="topLeft" :title="`${dispatchMode[text] || ''} 关联数据:${record.modeData || ''}`">
|
||||
<a-tooltip
|
||||
placement="topLeft"
|
||||
:title="`${dispatchMode[text] || ''} ${$tl('p.relatedData')}${record.modeData || ''}`"
|
||||
>
|
||||
<span>{{ dispatchMode[text] || '' }}</span>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
@ -101,22 +119,22 @@
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'status'">
|
||||
<!-- {{ dispatchStatusMap[text] || "未知" }} -->
|
||||
<a-tag v-if="text === 2" color="green">{{ dispatchStatusMap[text] || '未知' }}</a-tag>
|
||||
<a-tag v-if="text === 2" color="green">{{ dispatchStatusMap[text] || $tl('c.unknown') }}</a-tag>
|
||||
<a-tag v-else-if="text === 1 || text === 0 || text === 5" color="orange">{{
|
||||
dispatchStatusMap[text] || '未知'
|
||||
dispatchStatusMap[text] || $tl('c.unknown')
|
||||
}}</a-tag>
|
||||
<a-tag v-else-if="text === 3 || text === 4 || text === 6" color="red">{{
|
||||
dispatchStatusMap[text] || '未知'
|
||||
dispatchStatusMap[text] || $tl('c.unknown')
|
||||
}}</a-tag>
|
||||
<a-tag v-else>{{ dispatchStatusMap[text] || '未知' }}</a-tag>
|
||||
<a-tag v-else>{{ dispatchStatusMap[text] || $tl('c.unknown') }}</a-tag>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'operation'">
|
||||
<a-button type="primary" size="small" @click="handleDetail(record)">详情</a-button>
|
||||
<a-button type="primary" size="small" @click="handleDetail(record)">{{ $tl('p.details') }}</a-button>
|
||||
</template>
|
||||
</template>
|
||||
</CustomTable>
|
||||
<!-- 详情区 -->
|
||||
<a-modal v-model:open="detailVisible" destroy-on-close width="600px" title="详情信息" :footer="null">
|
||||
<a-modal v-model:open="detailVisible" destroy-on-close width="600px" :title="$tl('p.info')" :footer="null">
|
||||
<a-list item-layout="horizontal" :data-source="detailData">
|
||||
<template #renderItem="{ item }">
|
||||
<a-list-item>
|
||||
@ -156,49 +174,49 @@ export default {
|
||||
detailData: [],
|
||||
columns: [
|
||||
{
|
||||
title: '分发项目 ID',
|
||||
title: this.$tl('p.projectId'),
|
||||
dataIndex: 'outGivingId',
|
||||
width: 100,
|
||||
ellipsis: true
|
||||
},
|
||||
|
||||
{
|
||||
title: '节点名称',
|
||||
title: this.$tl('p.nodeName'),
|
||||
dataIndex: 'nodeName',
|
||||
ellipsis: true,
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '项目 ID',
|
||||
title: this.$tl('p.distributeId'),
|
||||
dataIndex: 'projectId',
|
||||
ellipsis: true,
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '分发方式',
|
||||
title: this.$tl('p.method'),
|
||||
dataIndex: 'mode',
|
||||
ellipsis: true,
|
||||
width: '100px'
|
||||
},
|
||||
{
|
||||
title: '分发结果',
|
||||
title: this.$tl('c.result'),
|
||||
dataIndex: 'outGivingResultMsg',
|
||||
ellipsis: true,
|
||||
width: 200
|
||||
},
|
||||
|
||||
{
|
||||
title: '分发耗时',
|
||||
title: this.$tl('p.duration'),
|
||||
dataIndex: 'outGivingResultTime',
|
||||
width: '120px'
|
||||
},
|
||||
{
|
||||
title: '文件大小',
|
||||
title: this.$tl('p.fileSize'),
|
||||
dataIndex: 'outGivingResultSize',
|
||||
width: '100px'
|
||||
},
|
||||
{
|
||||
title: '开始时间',
|
||||
title: this.$tl('p.startTime'),
|
||||
dataIndex: 'startTime',
|
||||
customRender: ({ text }) => {
|
||||
return parseTime(text)
|
||||
@ -207,7 +225,7 @@ export default {
|
||||
width: '170px'
|
||||
},
|
||||
{
|
||||
title: '结束时间',
|
||||
title: this.$tl('p.endTime'),
|
||||
dataIndex: 'endTime',
|
||||
sorter: true,
|
||||
customRender: ({ text }) => {
|
||||
@ -216,26 +234,26 @@ export default {
|
||||
width: '170px'
|
||||
},
|
||||
{
|
||||
title: '分发状态消息',
|
||||
title: this.$tl('p.statusMessage'),
|
||||
dataIndex: 'outGivingResultMsgData',
|
||||
ellipsis: true,
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '操作人',
|
||||
title: this.$tl('p.operator'),
|
||||
dataIndex: 'modifyUser',
|
||||
ellipsis: true,
|
||||
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
title: this.$tl('p.status'),
|
||||
dataIndex: 'status',
|
||||
width: 100,
|
||||
ellipsis: true,
|
||||
fixed: 'right'
|
||||
},
|
||||
{ title: '操作', dataIndex: 'operation', align: 'center', width: '100px', fixed: 'right' }
|
||||
{ title: this.$tl('p.action'), dataIndex: 'operation', align: 'center', width: '100px', fixed: 'right' }
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -251,6 +269,9 @@ export default {
|
||||
this.handleFilter()
|
||||
},
|
||||
methods: {
|
||||
$tl(key, ...args) {
|
||||
return this.$t(`pages.dispatch.log.${key}`, ...args)
|
||||
},
|
||||
readJsonStrField,
|
||||
// 搜索
|
||||
handleFilter() {
|
||||
@ -296,7 +317,7 @@ export default {
|
||||
this.detailVisible = true
|
||||
this.temp = Object.assign({}, record)
|
||||
|
||||
this.detailData.push({ title: '分发结果', description: this.temp.result })
|
||||
this.detailData.push({ title: this.$tl('c.result'), description: this.temp.result })
|
||||
},
|
||||
// 分页、排序、筛选变化时触发
|
||||
changePage(pagination, filters, sorter) {
|
||||
|
@ -16,15 +16,15 @@
|
||||
<a-space wrap class="search-box">
|
||||
<a-input
|
||||
v-model:value="listQuery['%name%']"
|
||||
placeholder="日志名称"
|
||||
:placeholder="$tl('c.logName')"
|
||||
class="search-input-item"
|
||||
@press-enter="loadData"
|
||||
/>
|
||||
|
||||
<a-tooltip title="按住 Ctr 或者 Alt/Option 键点击按钮快速回到第一页">
|
||||
<a-button type="primary" :loading="loading" @click="loadData">搜索</a-button>
|
||||
<a-tooltip :title="$tl('p.clickButtonToGoBackToFirstPage')">
|
||||
<a-button type="primary" :loading="loading" @click="loadData">{{ $tl('p.search') }}</a-button>
|
||||
</a-tooltip>
|
||||
<a-button type="primary" @click="handleAdd">新增</a-button>
|
||||
<a-button type="primary" @click="handleAdd">{{ $tl('c.action') }}</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
<template #bodyCell="{ column, text, record }">
|
||||
@ -36,9 +36,9 @@
|
||||
|
||||
<template v-else-if="column.dataIndex === 'operation'">
|
||||
<a-space>
|
||||
<a-button type="primary" size="small" @click="handleEdit(record)">编辑</a-button>
|
||||
<a-button type="primary" size="small" @click="handleLogRead(record)">查看</a-button>
|
||||
<a-button type="primary" danger size="small" @click="handleDelete(record)">删除</a-button>
|
||||
<a-button type="primary" size="small" @click="handleEdit(record)">{{ $tl('p.edit') }}</a-button>
|
||||
<a-button type="primary" size="small" @click="handleLogRead(record)">{{ $tl('p.view') }}</a-button>
|
||||
<a-button type="primary" danger size="small" @click="handleDelete(record)">{{ $tl('p.delete') }}</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
</template>
|
||||
@ -49,23 +49,23 @@
|
||||
destroy-on-close
|
||||
:confirm-loading="confirmLoading"
|
||||
width="60%"
|
||||
title="编辑日志搜索"
|
||||
:title="$tl('p.editLogSearch')"
|
||||
:mask-closable="false"
|
||||
@ok="handleEditOk"
|
||||
>
|
||||
<a-form ref="editForm" :rules="rules" :model="temp" :label-col="{ span: 4 }" :wrapper-col="{ span: 18 }">
|
||||
<a-form-item label="日志名称" name="name">
|
||||
<a-input v-model:value="temp.name" :max-length="50" placeholder="日志项目名称" />
|
||||
<a-form-item :label="$tl('c.logName')" name="name">
|
||||
<a-input v-model:value="temp.name" :max-length="50" :placeholder="$tl('p.logItemName')" />
|
||||
</a-form-item>
|
||||
<a-form-item label="绑定节点" required>
|
||||
<a-form-item :label="$tl('p.bindNode')" required>
|
||||
<a-space direction="vertical" style="width: 100%">
|
||||
<a-row v-for="(item, index) in temp.projectList" :key="index">
|
||||
<a-col :span="11">
|
||||
<span>节点: </span>
|
||||
<span>{{ $tl('p.node') }} </span>
|
||||
<a-select
|
||||
v-model:value="item.nodeId"
|
||||
style="width: 80%"
|
||||
placeholder="请选择节点"
|
||||
:placeholder="$tl('p.pleaseSelectNode')"
|
||||
@change="
|
||||
() => {
|
||||
temp = {
|
||||
@ -94,12 +94,12 @@
|
||||
</a-select>
|
||||
</a-col>
|
||||
<a-col :span="11">
|
||||
<span>项目: </span>
|
||||
<span>{{ $tl('p.project') }} </span>
|
||||
<a-select
|
||||
v-model:value="item.projectId"
|
||||
:disabled="!item.nodeId"
|
||||
style="width: 80%"
|
||||
:placeholder="`请选择项目`"
|
||||
:placeholder="`${$tl('p.pleaseSelectProject')}`"
|
||||
>
|
||||
<!-- <a-select-option value=""> 请先选择节点</a-select-option> -->
|
||||
<template v-if="nodeProjectList[item.nodeId]">
|
||||
@ -126,7 +126,7 @@
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-button type="primary" @click="() => temp.projectList.push({})">新增</a-button>
|
||||
<a-button type="primary" @click="() => temp.projectList.push({})">{{ $tl('c.action') }}</a-button>
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
@ -145,7 +145,7 @@
|
||||
"
|
||||
>
|
||||
<template #title>
|
||||
搜索查看
|
||||
{{ $tl('p.searchAndView') }}
|
||||
{{ temp.cacheData && temp.cacheData.logFile ? ':' + temp.cacheData.logFile : '' }}
|
||||
</template>
|
||||
<logReadView
|
||||
@ -187,14 +187,14 @@ export default {
|
||||
editVisible: false,
|
||||
columns: [
|
||||
{
|
||||
title: '名称',
|
||||
title: this.$tl('p.name'),
|
||||
dataIndex: 'name',
|
||||
ellipsis: true,
|
||||
tooltip: true
|
||||
},
|
||||
|
||||
{
|
||||
title: '修改人',
|
||||
title: this.$tl('p.modifier'),
|
||||
dataIndex: 'modifyUser',
|
||||
ellipsis: true,
|
||||
align: 'center',
|
||||
@ -202,7 +202,7 @@ export default {
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '修改时间',
|
||||
title: this.$tl('p.modificationTime'),
|
||||
dataIndex: 'modifyTimeMillis',
|
||||
sorter: true,
|
||||
customRender: ({ text }) => {
|
||||
@ -214,7 +214,7 @@ export default {
|
||||
width: 180
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
title: this.$tl('p.operation'),
|
||||
dataIndex: 'operation',
|
||||
ellipsis: true,
|
||||
|
||||
@ -223,7 +223,7 @@ export default {
|
||||
}
|
||||
],
|
||||
rules: {
|
||||
name: [{ required: true, message: '请填写日志项目名称', trigger: 'blur' }]
|
||||
name: [{ required: true, message: this.$tl('p.pleaseFillInLogItemName'), trigger: 'blur' }]
|
||||
},
|
||||
confirmLoading: false
|
||||
}
|
||||
@ -239,6 +239,9 @@ export default {
|
||||
this.loadData()
|
||||
},
|
||||
methods: {
|
||||
$tl(key, ...args) {
|
||||
return this.$t(`pages.dispatch.logRead.${key}`, ...args)
|
||||
},
|
||||
// 加载数据
|
||||
loadData(pointerEvent) {
|
||||
this.loading = true
|
||||
@ -314,7 +317,7 @@ export default {
|
||||
})
|
||||
if (!temp.projectList || !temp.projectList.length) {
|
||||
$notification.warn({
|
||||
message: '至少选择一个节点和项目'
|
||||
message: this.$tl('p.atLeastSelectOneNodeAndProject')
|
||||
})
|
||||
return false
|
||||
}
|
||||
@ -340,11 +343,11 @@ export default {
|
||||
// 删除
|
||||
handleDelete(record) {
|
||||
$confirm({
|
||||
title: '系统提示',
|
||||
title: this.$tl('p.systemPrompt'),
|
||||
zIndex: 1009,
|
||||
content: '真的要删除日志搜索么?',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
content: this.$tl('p.reallyDeleteLogSearch'),
|
||||
okText: this.$tl('p.confirm'),
|
||||
cancelText: this.$tl('p.cancel'),
|
||||
onOk: () => {
|
||||
return deleteLogRead(record.id).then((res) => {
|
||||
if (res.code === 200) {
|
||||
|
@ -7,11 +7,11 @@
|
||||
<div class="dir-container">
|
||||
<template v-if="temp.projectList && temp.cacheData">
|
||||
<a-form layout="inline" autocomplete="off">
|
||||
<a-form-item label="节点">
|
||||
<a-form-item :label="$tl('p.node')">
|
||||
<a-select
|
||||
:value="`${temp.cacheData.useNodeId},${temp.cacheData.useProjectId}`"
|
||||
style="width: 200px"
|
||||
placeholder="请选择节点"
|
||||
:placeholder="$tl('p.chooseNode')"
|
||||
@change="nodeChange"
|
||||
>
|
||||
<a-select-option v-for="item in temp.projectList" :key="`${item.nodeId},${item.projectId}`">
|
||||
@ -40,21 +40,21 @@
|
||||
<a-form layout="inline" autocomplete="off">
|
||||
<a-space direction="vertical" style="width: 100%">
|
||||
<a-space>
|
||||
<a-form-item label="搜关键词">
|
||||
<a-form-item :label="$tl('p.searchKeyword')">
|
||||
<!-- 关键词: -->
|
||||
<!-- ^.*\d+.*$ -->
|
||||
<!-- .*(0999996|0999995).* .*(a|b).* -->
|
||||
<a-tooltip placement="right" title="关键词高亮,支持正则(正则可能影响性能请酌情使用)">
|
||||
<a-tooltip placement="right" :title="$tl('p.keywordHighlight')">
|
||||
<a-input
|
||||
v-model:value="temp.cacheData.keyword"
|
||||
placeholder="关键词,支持正则"
|
||||
:placeholder="$tl('p.keywordRegex')"
|
||||
:style="`width: 250px`"
|
||||
@press-enter="sendSearchLog"
|
||||
>
|
||||
</a-input>
|
||||
</a-tooltip>
|
||||
</a-form-item>
|
||||
<a-form-item label="显示前N行">
|
||||
<a-form-item :label="$tl('p.showFirstNLines')">
|
||||
<a-input-number
|
||||
id="inputNumber"
|
||||
v-model:value="temp.cacheData.beforeCount"
|
||||
@ -63,7 +63,7 @@
|
||||
@press-enter="sendSearchLog"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="显示后N行">
|
||||
<a-form-item :label="$tl('p.showLastNLines')">
|
||||
<a-input-number
|
||||
id="inputNumber"
|
||||
v-model:value="temp.cacheData.afterCount"
|
||||
@ -72,26 +72,27 @@
|
||||
@press-enter="sendSearchLog"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-popover title="正则语法参考">
|
||||
<a-popover :title="$tl('p.regexReference')">
|
||||
<template #content>
|
||||
<ul>
|
||||
<li><b>^.*\d+.*$</b> - 匹配包含数字的行</li>
|
||||
<li><b>.*(a|b).*</b> - 匹配包含 a 或者 b 的行</li>
|
||||
<li><b>.*(异常).*</b> - 匹配包含 异常 的行</li>
|
||||
<li><b>^.*\d+.*$</b> - {{ $tl('p.matchLinesWithNumbers') }}</li>
|
||||
<li><b>.*(a|b).*</b> - {{ $tl('p.matchLinesWithAorB') }}</li>
|
||||
<li>
|
||||
<b>.*({{ $tl('p.exception') }}).*</b> - {{ $tl('p.matchLinesWithException') }}
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
<a-button type="link" style="padding: 0"
|
||||
><UnorderedListOutlined /><span style="margin-left: 2px">语法参考</span></a-button
|
||||
><UnorderedListOutlined /><span style="margin-left: 2px">{{
|
||||
$tl('p.syntaxReference')
|
||||
}}</span></a-button
|
||||
>
|
||||
</a-popover>
|
||||
</a-space>
|
||||
<a-space>
|
||||
<a-form-item label="搜索模式">
|
||||
<a-form-item :label="$tl('p.searchMode')">
|
||||
<!-- -->
|
||||
<a-tooltip
|
||||
placement="right"
|
||||
title="搜索模式,默认查看文件最后多少行,从头搜索指从指定行往下搜索,从尾搜索指从文件尾往上搜索多少行"
|
||||
>
|
||||
<a-tooltip placement="right" :title="$tl('p.searchModeDescription')">
|
||||
<a-select
|
||||
:style="`width: 250px`"
|
||||
:value="temp.cacheData.first"
|
||||
@ -103,12 +104,12 @@
|
||||
}
|
||||
"
|
||||
>
|
||||
<a-select-option value="false">从尾搜索</a-select-option>
|
||||
<a-select-option value="true">从头搜索 </a-select-option>
|
||||
<a-select-option value="false">{{ $tl('p.searchFromEnd') }}</a-select-option>
|
||||
<a-select-option value="true">{{ $tl('p.searchFromStart') }} </a-select-option>
|
||||
</a-select>
|
||||
</a-tooltip>
|
||||
</a-form-item>
|
||||
<a-form-item label="文件前N行">
|
||||
<a-form-item :label="$tl('p.firstNFileLines')">
|
||||
<a-input-number
|
||||
id="inputNumber"
|
||||
v-model:value="temp.cacheData.head"
|
||||
@ -117,7 +118,7 @@
|
||||
@press-enter="sendSearchLog"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="文件后N行">
|
||||
<a-form-item :label="$tl('p.lastNFileLines')">
|
||||
<a-input-number
|
||||
id="inputNumber"
|
||||
v-model:value="temp.cacheData.tail"
|
||||
@ -126,20 +127,36 @@
|
||||
@press-enter="sendSearchLog"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-popover title="搜索配置参考">
|
||||
<a-popover :title="$tl('p.searchConfigReference')">
|
||||
<template #content>
|
||||
<ul>
|
||||
<li><b>从尾搜索、文件前0行、文件后3行</b> - 在文件最后 3 行中搜索</li>
|
||||
<li><b>从头搜索、文件前0行、文件后3行</b> - 在文件第 3 - 2147483647 行中搜索</li>
|
||||
<li><b>从尾搜索、文件前2行、文件后3行</b> - 在文件第 1 - 2 行中搜索</li>
|
||||
<li><b>从尾搜索、文件前100行、文件后100行</b> - 在文件第 1 - 100 行中搜索</li>
|
||||
<li><b>从头搜索、文件前2行、文件后3行</b> - 在文件第 2 - 2 行中搜索</li>
|
||||
<li><b>从尾搜索、文件前20行、文件后3行</b> - 在文件第 17 - 20 行中搜索</li>
|
||||
<li><b>从头搜索、文件前20行、文件后3行</b> - 在文件第 3 - 20 行中搜索</li>
|
||||
<li>
|
||||
<b>{{ $tl('p.searchFromEndExample1') }}</b> - {{ $tl('p.searchLastNLines') }}
|
||||
</li>
|
||||
<li>
|
||||
<b>{{ $tl('p.searchFromStartExample1') }}</b> - {{ $tl('p.searchLineRange1') }}
|
||||
</li>
|
||||
<li>
|
||||
<b>{{ $tl('p.searchFromEndExample2') }}</b> - {{ $tl('p.searchLineRange2') }}
|
||||
</li>
|
||||
<li>
|
||||
<b>{{ $tl('p.searchFromEndExample3') }}</b> - {{ $tl('p.searchLineRange3') }}
|
||||
</li>
|
||||
<li>
|
||||
<b>{{ $tl('p.searchFromStartExample2') }}</b> - {{ $tl('p.searchLineRange4') }}
|
||||
</li>
|
||||
<li>
|
||||
<b>{{ $tl('p.searchFromEndExample4') }}</b> - {{ $tl('p.searchLineRange5') }}
|
||||
</li>
|
||||
<li>
|
||||
<b>{{ $tl('p.searchFromStartExample3') }}</b> - {{ $tl('p.searchLineRange6') }}
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
<a-button type="link" style="padding: 0"
|
||||
><UnorderedListOutlined /><span style="margin-left: 2px">搜索参考</span></a-button
|
||||
><UnorderedListOutlined /><span style="margin-left: 2px">{{
|
||||
$tl('p.searchReference')
|
||||
}}</span></a-button
|
||||
>
|
||||
</a-popover>
|
||||
</a-space></a-space
|
||||
@ -264,9 +281,7 @@ export default {
|
||||
})[0]
|
||||
const socketUrl = getWebSocketUrl(
|
||||
'/socket/console',
|
||||
`userId=${this.getLongTermToken()}&id=${itemProjectData?.id}&nodeId=${
|
||||
item.nodeId
|
||||
}&type=console&workspaceId=${this.getWorkspaceId()}`
|
||||
`userId=${this.getLongTermToken()}&id=${itemProjectData?.id}&nodeId=${item.nodeId}&type=console&workspaceId=${this.getWorkspaceId()}`
|
||||
)
|
||||
const domId = `pre-dom-${item.nodeId},${item.projectId}`
|
||||
this.socketCache = { ...this.socketCache, [domId]: {} }
|
||||
@ -302,6 +317,9 @@ export default {
|
||||
this.close()
|
||||
},
|
||||
methods: {
|
||||
$tl(key, ...args) {
|
||||
return this.$t(`pages.dispatch.logReadView.${key}`, ...args)
|
||||
},
|
||||
close() {
|
||||
Object.keys(this.socketCache).forEach((item) => {
|
||||
clearInterval(this.socketCache[item].heart)
|
||||
@ -315,7 +333,7 @@ export default {
|
||||
console.error(err)
|
||||
$notification.error({
|
||||
key: 'log-read-error',
|
||||
message: 'web socket 错误,请检查是否开启 ws 代理'
|
||||
message: `web socket ${this.$tl('p.error')},${this.$tl('p.checkWsProxy')}`
|
||||
})
|
||||
clearInterval(this.socketCache[id].heart)
|
||||
}
|
||||
@ -324,7 +342,9 @@ export default {
|
||||
console.error(err)
|
||||
$notification.info({
|
||||
key: 'log-read-close',
|
||||
message: ((this.nodeName[item.nodeId] && this.nodeName[item.nodeId].name) || '') + ' 会话已经关闭[tail-log]-'
|
||||
message:
|
||||
((this.nodeName[item.nodeId] && this.nodeName[item.nodeId].name) || '') +
|
||||
` ${this.$tl('p.sessionClosed')}[tail-log]-`
|
||||
})
|
||||
clearInterval(this.socketCache[id].heart)
|
||||
}
|
||||
@ -421,7 +441,7 @@ export default {
|
||||
this.sendSearchLog()
|
||||
} else {
|
||||
//
|
||||
$message.error('当前文件不可读,需要配置可读文件授权')
|
||||
$message.error(this.$tl('p.fileNotReadable'))
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -8,7 +8,7 @@
|
||||
:footer="uploading ? null : undefined"
|
||||
width="50%"
|
||||
:keyboard="false"
|
||||
:title="'分发项目-' + data.name"
|
||||
:title="$tl('p.distributeProject') + data.name"
|
||||
:mask-closable="false"
|
||||
@ok="handleDispatchOk"
|
||||
@cancel="
|
||||
@ -18,37 +18,39 @@
|
||||
"
|
||||
>
|
||||
<a-form ref="dispatchForm" :rules="rules" :model="temp" :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }">
|
||||
<a-form-item label="方式" name="type">
|
||||
<a-form-item :label="$tl('p.method')" name="type">
|
||||
<a-radio-group v-model:value="temp.type" name="type" :disabled="!!percentage" @change="restForm">
|
||||
<a-radio :value="'use-build'">构建产物</a-radio>
|
||||
<a-radio :value="'file-storage'">文件中心</a-radio>
|
||||
<a-radio :value="'static-file-storage'">静态文件</a-radio>
|
||||
<a-radio :value="'upload'">上传文件</a-radio>
|
||||
<a-radio :value="'download'">远程下载</a-radio>
|
||||
<a-radio :value="'use-build'">{{ $tl('p.buildProduct') }}</a-radio>
|
||||
<a-radio :value="'file-storage'">{{ $tl('p.fileCenter') }}</a-radio>
|
||||
<a-radio :value="'static-file-storage'">{{ $tl('p.staticFile') }}</a-radio>
|
||||
<a-radio :value="'upload'">{{ $tl('p.uploadFile') }}</a-radio>
|
||||
<a-radio :value="'download'">{{ $tl('p.remoteDownload') }}</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<!-- 手动上传 -->
|
||||
<a-form-item v-if="temp.type === 'upload'" label="选择分发文件" name="clearOld">
|
||||
<a-form-item v-if="temp.type === 'upload'" :label="$tl('p.selectDistributeFile')" name="clearOld">
|
||||
<a-progress v-if="percentage" :percent="percentage">
|
||||
<template #format="percent">
|
||||
{{ percent }}%
|
||||
<template v-if="percentageInfo.total"> ({{ renderSize(percentageInfo.total) }}) </template>
|
||||
<template v-if="percentageInfo.duration"> 用时:{{ formatDuration(percentageInfo.duration) }} </template>
|
||||
<template v-if="percentageInfo.duration">
|
||||
{{ $tl('p.usedTime') }}:{{ formatDuration(percentageInfo.duration) }}
|
||||
</template>
|
||||
</template>
|
||||
</a-progress>
|
||||
|
||||
<a-upload :file-list="fileList" :disabled="!!percentage" :before-upload="beforeUpload" @remove="handleRemove">
|
||||
<LoadingOutlined v-if="percentage" />
|
||||
<a-button v-else type="primary"><UploadOutlined />选择文件</a-button>
|
||||
<a-button v-else type="primary"><UploadOutlined />{{ $tl('c.selectFile') }}</a-button>
|
||||
</a-upload>
|
||||
</a-form-item>
|
||||
<!-- 远程下载 -->
|
||||
<a-form-item v-else-if="temp.type === 'download'" label="远程下载URL" name="url">
|
||||
<a-input v-model:value="temp.url" placeholder="远程下载地址" />
|
||||
<a-form-item v-else-if="temp.type === 'download'" :label="$tl('p.remoteDownloadURL')" name="url">
|
||||
<a-input v-model:value="temp.url" :placeholder="$tl('p.remoteDownloadAddress')" />
|
||||
</a-form-item>
|
||||
<!-- 在线构建 -->
|
||||
<template v-else-if="temp.type == 'use-build'">
|
||||
<a-form-item label="选择构建">
|
||||
<a-form-item :label="$tl('c.selectBuild')">
|
||||
<a-space>
|
||||
{{ chooseBuildInfo.name }}
|
||||
<a-button
|
||||
@ -59,11 +61,11 @@
|
||||
}
|
||||
"
|
||||
>
|
||||
选择构建
|
||||
{{ $tl('c.selectBuild') }}
|
||||
</a-button>
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
<a-form-item label="选择产物">
|
||||
<a-form-item :label="$tl('c.selectProduct')">
|
||||
<a-space>
|
||||
<a-tag v-if="chooseBuildInfo.buildNumberId">#{{ chooseBuildInfo.buildNumberId }}</a-tag>
|
||||
<a-button
|
||||
@ -75,14 +77,14 @@
|
||||
}
|
||||
"
|
||||
>
|
||||
选择产物
|
||||
{{ $tl('c.selectProduct') }}
|
||||
</a-button>
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
</template>
|
||||
<!-- 文件中心 -->
|
||||
<template v-else-if="temp.type === 'file-storage'">
|
||||
<a-form-item label="选择文件">
|
||||
<a-form-item :label="$tl('c.selectFile')">
|
||||
<a-space>
|
||||
{{ chooseFileInfo.name }}
|
||||
<a-button
|
||||
@ -93,14 +95,14 @@
|
||||
}
|
||||
"
|
||||
>
|
||||
选择文件
|
||||
{{ $tl('c.selectFile') }}
|
||||
</a-button>
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
</template>
|
||||
<!-- 静态文件 -->
|
||||
<template v-else-if="temp.type === 'static-file-storage'">
|
||||
<a-form-item label="选择文件">
|
||||
<a-form-item :label="$tl('c.selectFile')">
|
||||
<a-space>
|
||||
{{ chooseFileInfo.name }}
|
||||
<a-button
|
||||
@ -111,54 +113,62 @@
|
||||
}
|
||||
"
|
||||
>
|
||||
选择文件
|
||||
{{ $tl('c.selectFile') }}
|
||||
</a-button>
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
</template>
|
||||
<a-form-item name="clearOld">
|
||||
<template #label>
|
||||
清空发布
|
||||
{{ $tl('p.clearPublish') }}
|
||||
<a-tooltip>
|
||||
<template #title>
|
||||
清空发布是指在上传新文件前,会将项目文件夹目录里面的所有文件先删除后再保存新文件
|
||||
</template>
|
||||
<template #title> {{ $tl('undefined') }},{{ $tl('undefined') }} </template>
|
||||
<QuestionCircleOutlined />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<a-switch v-model:checked="temp.clearOld" checked-children="是" un-checked-children="否" />
|
||||
<a-switch
|
||||
v-model:checked="temp.clearOld"
|
||||
:checked-children="$tl('c.yes')"
|
||||
:un-checked-children="$tl('c.no')"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="temp.type !== 'use-build'" name="unzip">
|
||||
<template #label>
|
||||
是否解压
|
||||
{{ $tl('p.unZip') }}
|
||||
<a-tooltip>
|
||||
<template #title>
|
||||
如果上传的压缩文件是否自动解压 支持的压缩包类型有 tar.bz2, tar.gz, tar, bz2, zip, gz
|
||||
</template>
|
||||
<template #title> {{ $tl('p.autoUnZip') }}.bz2, tar.gz, tar, bz2, zip, gz </template>
|
||||
<QuestionCircleOutlined />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<a-switch v-model:checked="temp.autoUnzip" checked-children="是" un-checked-children="否" />
|
||||
<a-switch
|
||||
v-model:checked="temp.autoUnzip"
|
||||
:checked-children="$tl('c.yes')"
|
||||
:un-checked-children="$tl('c.no')"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="temp.autoUnzip" label="剔除文件夹">
|
||||
<a-form-item v-if="temp.autoUnzip" :label="$tl('p.excludeFolder')">
|
||||
<a-input-number
|
||||
v-model:value="temp.stripComponents"
|
||||
style="width: 100%"
|
||||
:min="0"
|
||||
placeholder="解压时候自动剔除压缩包里面多余的文件夹名"
|
||||
:placeholder="$tl('p.excludeFolderDescription')"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="分发后操作" name="afterOpt">
|
||||
<a-select v-model:value="temp.afterOpt" placeholder="请选择发布后操作">
|
||||
<a-form-item :label="$tl('p.postPublishAction')" name="afterOpt">
|
||||
<a-select v-model:value="temp.afterOpt" :placeholder="$tl('c.selectPostPublishAction')">
|
||||
<a-select-option v-for="item in afterOptList" :key="item.value">{{ item.title }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item name="secondaryDirectory" label="二级目录">
|
||||
<a-input v-model:value="temp.secondaryDirectory" placeholder="不填写则发布至项目的根目录" />
|
||||
<a-form-item name="secondaryDirectory" :label="$tl('p.subDirectory')">
|
||||
<a-input v-model:value="temp.secondaryDirectory" :placeholder="$tl('p.subDirectoryDescription')" />
|
||||
</a-form-item>
|
||||
<a-form-item name="selectProject" label="筛选项目" help="筛选之后本次发布操作只发布筛选项,并且只对本次操作生效">
|
||||
<a-select v-model:value="temp.selectProjectArray" mode="multiple" placeholder="请选择指定发布的项目">
|
||||
<a-form-item name="selectProject" :label="$tl('p.filterProject')" :help="$tl('p.filterProjectDescription')">
|
||||
<a-select
|
||||
v-model:value="temp.selectProjectArray"
|
||||
mode="multiple"
|
||||
:placeholder="$tl('p.selectPublishProject')"
|
||||
>
|
||||
<a-select-option v-for="item in itemProjectList" :key="item.id" :value="`${item.projectId}@${item.nodeId}`">
|
||||
{{ item.nodeName }}-{{ item.cacheProjectName || item.projectId }}
|
||||
</a-select-option>
|
||||
@ -169,7 +179,7 @@
|
||||
<!-- 选择构建 -->
|
||||
<a-drawer
|
||||
destroy-on-close
|
||||
:title="`选择构建`"
|
||||
:title="`${$tl('c.selectBuild')}`"
|
||||
placement="right"
|
||||
:open="chooseVisible === 1"
|
||||
width="80vw"
|
||||
@ -211,7 +221,7 @@
|
||||
}
|
||||
"
|
||||
>
|
||||
取消
|
||||
{{ $tl('c.cancel') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
type="primary"
|
||||
@ -221,7 +231,7 @@
|
||||
}
|
||||
"
|
||||
>
|
||||
确认
|
||||
{{ $tl('c.confirm') }}
|
||||
</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
@ -229,7 +239,7 @@
|
||||
<!-- 选择构建产物 -->
|
||||
<a-drawer
|
||||
destroy-on-close
|
||||
:title="`选择构建产物`"
|
||||
:title="`${$tl('p.selectBuildProduct')}`"
|
||||
placement="right"
|
||||
:open="chooseVisible === 2"
|
||||
width="80vw"
|
||||
@ -272,7 +282,7 @@
|
||||
}
|
||||
"
|
||||
>
|
||||
取消
|
||||
{{ $tl('c.cancel') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
type="primary"
|
||||
@ -282,7 +292,7 @@
|
||||
}
|
||||
"
|
||||
>
|
||||
确认
|
||||
{{ $tl('c.confirm') }}
|
||||
</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
@ -290,7 +300,7 @@
|
||||
<!-- 选择文件 -->
|
||||
<a-drawer
|
||||
destroy-on-close
|
||||
:title="`选择文件`"
|
||||
:title="`${$tl('c.selectFile')}`"
|
||||
placement="right"
|
||||
:open="chooseVisible === 3"
|
||||
width="80vw"
|
||||
@ -329,7 +339,7 @@
|
||||
}
|
||||
"
|
||||
>
|
||||
取消
|
||||
{{ $tl('c.cancel') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
type="primary"
|
||||
@ -339,7 +349,7 @@
|
||||
}
|
||||
"
|
||||
>
|
||||
确认
|
||||
{{ $tl('c.confirm') }}
|
||||
</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
@ -347,7 +357,7 @@
|
||||
<!-- 选择静态文件 -->
|
||||
<a-drawer
|
||||
destroy-on-close
|
||||
:title="`选择静态文件`"
|
||||
:title="`${$tl('p.selectStaticFile')}`"
|
||||
placement="right"
|
||||
:open="chooseVisible === 4"
|
||||
width="80vw"
|
||||
@ -386,7 +396,7 @@
|
||||
}
|
||||
"
|
||||
>
|
||||
取消
|
||||
{{ $tl('c.cancel') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
type="primary"
|
||||
@ -396,7 +406,7 @@
|
||||
}
|
||||
"
|
||||
>
|
||||
确认
|
||||
{{ $tl('c.confirm') }}
|
||||
</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
@ -448,8 +458,8 @@ export default {
|
||||
itemProjectList: [],
|
||||
fileList: [],
|
||||
rules: {
|
||||
afterOpt: [{ required: true, message: '请选择发布后操作', trigger: 'blur' }],
|
||||
url: [{ required: true, message: '请输入远程地址', trigger: 'blur' }]
|
||||
afterOpt: [{ required: true, message: this.$tl('c.selectPostPublishAction'), trigger: 'blur' }],
|
||||
url: [{ required: true, message: this.$tl('p.pleaseInputRemoteAddress'), trigger: 'blur' }]
|
||||
},
|
||||
temp: { type: 'upload' },
|
||||
chooseVisible: 0,
|
||||
@ -518,6 +528,9 @@ export default {
|
||||
// console.log(this.temp);
|
||||
},
|
||||
methods: {
|
||||
$tl(key, ...args) {
|
||||
return this.$t(`pages.dispatch.start.${key}`, ...args)
|
||||
},
|
||||
renderSize,
|
||||
formatDuration,
|
||||
// 处理文件移除
|
||||
@ -548,7 +561,7 @@ export default {
|
||||
// 判断文件
|
||||
if (this.fileList.length === 0) {
|
||||
$notification.error({
|
||||
message: '请选择文件'
|
||||
message: this.$tl('p.pleaseSelectFile')
|
||||
})
|
||||
return false
|
||||
}
|
||||
@ -635,7 +648,7 @@ export default {
|
||||
} else if (this.temp.type == 'download') {
|
||||
if (!this.temp.url) {
|
||||
$notification.error({
|
||||
message: '请填写远程URL'
|
||||
message: this.$tl('p.pleaseFillRemoteURL')
|
||||
})
|
||||
return false
|
||||
}
|
||||
@ -658,7 +671,7 @@ export default {
|
||||
// 构建
|
||||
if (!this.chooseBuildInfo || !this.chooseBuildInfo.id || !this.chooseBuildInfo.buildNumberId) {
|
||||
$notification.error({
|
||||
message: '请填写构建和产物'
|
||||
message: this.$tl('p.pleaseFillBuildAndProduct')
|
||||
})
|
||||
return false
|
||||
}
|
||||
@ -685,7 +698,7 @@ export default {
|
||||
// 文件中心
|
||||
if (!this.chooseFileInfo || !this.chooseFileInfo.id) {
|
||||
$notification.error({
|
||||
message: '请选择文件中心的文件'
|
||||
message: this.$tl('p.pleaseSelectFileCenterFile')
|
||||
})
|
||||
return false
|
||||
}
|
||||
@ -711,7 +724,7 @@ export default {
|
||||
// 文件中心
|
||||
if (!this.chooseFileInfo || !this.chooseFileInfo.id) {
|
||||
$notification.error({
|
||||
message: '请选择静态文件中的文件'
|
||||
message: this.$tl('p.pleaseSelectStaticFileFile')
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
<div>
|
||||
<a-drawer
|
||||
destroy-on-close
|
||||
:title="`查看 ${name} 状态`"
|
||||
:title="`${$tl('p.view')} ${name} ${$tl('c.status')}`"
|
||||
placement="right"
|
||||
width="85vw"
|
||||
:open="true"
|
||||
@ -13,7 +13,7 @@
|
||||
"
|
||||
>
|
||||
<a-tabs v-model:activeKey="tabKey" tab-position="left">
|
||||
<a-tab-pane key="1" tab="状态">
|
||||
<a-tab-pane key="1" :tab="$tl('c.status')">
|
||||
<!-- 嵌套表格 -->
|
||||
<a-table
|
||||
:loading="childLoading"
|
||||
@ -30,22 +30,24 @@
|
||||
<template #title>
|
||||
<a-space>
|
||||
<div>
|
||||
当前状态:
|
||||
<a-tag v-if="data.status === 2" color="green">{{ statusMap[data.status] || '未知' }}</a-tag>
|
||||
{{ $tl('p.currentStatus') }}
|
||||
<a-tag v-if="data.status === 2" color="green">{{ statusMap[data.status] || $tl('c.unknown') }}</a-tag>
|
||||
<a-tag v-else-if="data.status === 1 || data.status === 0" color="orange">{{
|
||||
statusMap[data.status] || '未知'
|
||||
statusMap[data.status] || $tl('c.unknown')
|
||||
}}</a-tag>
|
||||
<a-tag v-else-if="data.status === 3 || data.status === 4" color="red">{{
|
||||
statusMap[data.status] || '未知'
|
||||
statusMap[data.status] || $tl('c.unknown')
|
||||
}}</a-tag>
|
||||
<a-tag v-else>{{ statusMap[data.status] || '未知' }}</a-tag>
|
||||
<a-tag v-else>{{ statusMap[data.status] || $tl('c.unknown') }}</a-tag>
|
||||
</div>
|
||||
<div>状态描述:{{ data.statusMsg || '-' }}</div>
|
||||
<a-button type="primary" size="small" :loading="childLoading" @click="loadData">刷新</a-button>
|
||||
<div>{{ $tl('p.statusDescription') }}{{ data.statusMsg || '-' }}</div>
|
||||
<a-button type="primary" size="small" :loading="childLoading" @click="loadData">{{
|
||||
$tl('p.refresh')
|
||||
}}</a-button>
|
||||
|
||||
<a-statistic-countdown
|
||||
format=" s 秒"
|
||||
title="刷新倒计时"
|
||||
format=" {{$tl('p.seconds')}}"
|
||||
:title="$tl('p.refreshCountdown')"
|
||||
:value="countdownTime"
|
||||
@finish="silenceLoadData"
|
||||
/>
|
||||
@ -63,7 +65,7 @@
|
||||
<template v-else-if="column.dataIndex === 'projectName'">
|
||||
<a-tooltip placement="topLeft" :title="text">
|
||||
<template v-if="record.disabled">
|
||||
<a-tooltip title="当前项目被禁用">
|
||||
<a-tooltip :title="$tl('p.currentProjectDisabled')">
|
||||
<EyeInvisibleOutlined />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
@ -71,14 +73,14 @@
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'outGivingStatus'">
|
||||
<a-tag v-if="text === 2" color="green">{{ dispatchStatusMap[text] || '未知' }}</a-tag>
|
||||
<a-tag v-if="text === 2" color="green">{{ dispatchStatusMap[text] || $tl('c.unknown') }}</a-tag>
|
||||
<a-tag v-else-if="text === 1 || text === 0 || text === 5" color="orange">{{
|
||||
dispatchStatusMap[text] || '未知'
|
||||
dispatchStatusMap[text] || $tl('c.unknown')
|
||||
}}</a-tag>
|
||||
<a-tag v-else-if="text === 3 || text === 4 || text === 6" color="red">{{
|
||||
dispatchStatusMap[text] || '未知'
|
||||
dispatchStatusMap[text] || $tl('c.unknown')
|
||||
}}</a-tag>
|
||||
<a-tag v-else>{{ dispatchStatusMap[text] || '未知' }}</a-tag>
|
||||
<a-tag v-else>{{ dispatchStatusMap[text] || $tl('c.unknown') }}</a-tag>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'outGivingResultMsg'">
|
||||
<a-tooltip placement="topLeft" :title="readJsonStrField(record.outGivingResult, 'msg')">
|
||||
@ -117,15 +119,15 @@
|
||||
:checked="text"
|
||||
:disabled="true"
|
||||
size="small"
|
||||
checked-children="运行中"
|
||||
un-checked-children="未运行"
|
||||
:checked-children="$tl('p.running')"
|
||||
:un-checked-children="$tl('p.notRunning')"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template v-else-if="column.dataIndex === 'projectPid'">
|
||||
<a-tooltip
|
||||
placement="topLeft"
|
||||
:title="`进程号:${record.projectPid || '-'} / 端口号:${record.projectPort || '-'}`"
|
||||
:title="`${$tl('p.processId')}${record.projectPid || '-'} / ${$tl('p.portNumber')}${record.projectPort || '-'}`"
|
||||
>
|
||||
<span>{{ record.projectPid || '-' }}/{{ record.projectPort || '-' }}</span>
|
||||
</a-tooltip>
|
||||
@ -133,18 +135,22 @@
|
||||
|
||||
<template v-else-if="column.dataIndex === 'child-operation'">
|
||||
<a-space>
|
||||
<a-button size="small" :disabled="!record.projectName" type="primary" @click="handleFile(record)"
|
||||
>文件</a-button
|
||||
>
|
||||
<a-button size="small" :disabled="!record.projectName" type="primary" @click="handleConsole(record)"
|
||||
>控制台</a-button
|
||||
<a-button size="small" :disabled="!record.projectName" type="primary" @click="handleFile(record)">{{
|
||||
$tl('p.file')
|
||||
}}</a-button>
|
||||
<a-button
|
||||
size="small"
|
||||
:disabled="!record.projectName"
|
||||
type="primary"
|
||||
@click="handleConsole(record)"
|
||||
>{{ $tl('c.console') }}</a-button
|
||||
>
|
||||
</a-space>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="2" tab="配置">
|
||||
<a-tab-pane key="2" :tab="$tl('p.configuration')">
|
||||
<!-- 配置分发 -->
|
||||
<div style="width: 50vw">
|
||||
<!-- list -->
|
||||
@ -152,14 +158,14 @@
|
||||
<Draggable v-for="(element, index) in list" :key="index">
|
||||
<a-row class="item-row">
|
||||
<a-col :span="18">
|
||||
<span> 节点名: {{ element.nodeName }} </span>
|
||||
<span> 项目名: {{ element.cacheProjectName }} </span>
|
||||
<span> {{ $tl('p.nodeName') }} {{ element.nodeName }} </span>
|
||||
<span> {{ $tl('p.projectName') }} {{ element.cacheProjectName }} </span>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-space>
|
||||
<a-switch
|
||||
checked-children="启用"
|
||||
un-checked-children="禁用"
|
||||
:checked-children="$tl('p.enable')"
|
||||
:un-checked-children="$tl('p.disable')"
|
||||
:checked="element.disabled ? false : true"
|
||||
@change="
|
||||
(checked) => {
|
||||
@ -180,9 +186,9 @@
|
||||
:disabled="!list || list.length <= 1"
|
||||
@click="handleRemoveProject(element)"
|
||||
>
|
||||
解绑
|
||||
{{ $tl('p.unbind') }}
|
||||
</a-button>
|
||||
<a-tooltip placement="left" :title="`长按可以拖动排序`" class="move">
|
||||
<a-tooltip placement="left" :title="`${$tl('p.longPressToDragAndSort')}`" class="move">
|
||||
<MenuOutlined />
|
||||
</a-tooltip>
|
||||
</a-space>
|
||||
@ -192,7 +198,7 @@
|
||||
</Container>
|
||||
<a-col style="margin-top: 10px">
|
||||
<a-space>
|
||||
<a-button type="primary" size="small" @click="viewDispatchManagerOk">保存</a-button>
|
||||
<a-button type="primary" size="small" @click="viewDispatchManagerOk">{{ $tl('p.save') }}</a-button>
|
||||
</a-space>
|
||||
</a-col>
|
||||
</div>
|
||||
@ -316,65 +322,65 @@ export default {
|
||||
|
||||
childColumns: [
|
||||
{
|
||||
title: '节点名称',
|
||||
title: this.$tl('p.nodeNameLabel'),
|
||||
dataIndex: 'nodeId',
|
||||
width: 120,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '项目名称',
|
||||
title: this.$tl('p.projectNameLabel'),
|
||||
dataIndex: 'projectName',
|
||||
width: 120,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '项目状态',
|
||||
title: this.$tl('p.projectStatusLabel'),
|
||||
dataIndex: 'projectStatus',
|
||||
width: 120,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '进程/端口',
|
||||
title: this.$tl('p.processPortLabel'),
|
||||
dataIndex: 'projectPid',
|
||||
width: '120px',
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '分发状态',
|
||||
title: this.$tl('p.distributionStatusLabel'),
|
||||
dataIndex: 'outGivingStatus',
|
||||
width: '120px'
|
||||
},
|
||||
{
|
||||
title: '分发结果',
|
||||
title: this.$tl('p.distributionResultLabel'),
|
||||
dataIndex: 'outGivingResultMsg',
|
||||
ellipsis: true,
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '分发状态消息',
|
||||
title: this.$tl('p.distributionStatusMessageLabel'),
|
||||
dataIndex: 'outGivingResultMsgData',
|
||||
ellipsis: true,
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '分发耗时',
|
||||
title: this.$tl('p.distributionDurationLabel'),
|
||||
dataIndex: 'outGivingResultTime',
|
||||
width: '120px'
|
||||
},
|
||||
{
|
||||
title: '文件大小',
|
||||
title: this.$tl('p.fileSizeLabel'),
|
||||
dataIndex: 'outGivingResultSize',
|
||||
width: '100px'
|
||||
},
|
||||
{
|
||||
title: '最后分发时间',
|
||||
title: this.$tl('p.lastDistributionTimeLabel'),
|
||||
dataIndex: 'lastTime',
|
||||
width: '170px',
|
||||
ellipsis: true,
|
||||
customRender: ({ text }) => parseTime(text)
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
title: this.$tl('p.operationLabel'),
|
||||
dataIndex: 'child-operation',
|
||||
fixed: 'right',
|
||||
|
||||
@ -395,6 +401,9 @@ export default {
|
||||
this.loadNodeList()
|
||||
},
|
||||
methods: {
|
||||
$tl(key, ...args) {
|
||||
return this.$t(`pages.dispatch.status.${key}`, ...args)
|
||||
},
|
||||
readJsonStrField,
|
||||
renderSize,
|
||||
formatDuration,
|
||||
@ -540,7 +549,7 @@ export default {
|
||||
...element,
|
||||
projectStatus: false,
|
||||
projectPid: '-',
|
||||
errorMsg: '网络异常'
|
||||
errorMsg: this.$tl('p.networkError')
|
||||
}
|
||||
}
|
||||
return element
|
||||
@ -555,7 +564,7 @@ export default {
|
||||
// 文件管理
|
||||
handleFile(record) {
|
||||
this.temp = Object.assign({}, record)
|
||||
this.drawerTitle = `文件管理(${this.temp.projectId})`
|
||||
this.drawerTitle = `${this.$tl('p.fileManagement')}(${this.temp.projectId})`
|
||||
this.drawerFileVisible = true
|
||||
},
|
||||
// 关闭文件管理对话框
|
||||
@ -565,7 +574,7 @@ export default {
|
||||
// 控制台
|
||||
handleConsole(record) {
|
||||
this.temp = Object.assign({}, record)
|
||||
this.drawerTitle = `控制台(${this.temp.projectId})`
|
||||
this.drawerTitle = `${this.$tl('c.console')}(${this.temp.projectId})`
|
||||
this.drawerConsoleVisible = true
|
||||
},
|
||||
// 关闭控制台
|
||||
@ -590,7 +599,7 @@ export default {
|
||||
this.onFileClose()
|
||||
this.drawerReadFileVisible = true
|
||||
this.temp.readFilePath = (path + '/' + filename).replace(new RegExp('//', 'gm'), '/')
|
||||
this.drawerTitle = `跟踪文件(${filename})`
|
||||
this.drawerTitle = `${this.$tl('p.trackFile')}(${filename})`
|
||||
},
|
||||
onReadFileClose() {
|
||||
this.drawerReadFileVisible = false
|
||||
@ -609,21 +618,24 @@ export default {
|
||||
},
|
||||
// 删除项目
|
||||
handleRemoveProject(item) {
|
||||
const html =
|
||||
"<b style='font-size: 20px;'>真的要释放(删除)当前项目么?</b>" +
|
||||
"<ul style='font-size: 20px;color:red;font-weight: bold;'>" +
|
||||
'<li>不会真实请求节点删除项目信息</b></li>' +
|
||||
'<li>一般用于服务器无法连接且已经确定不再使用</li>' +
|
||||
'<li>如果误操作会产生冗余数据!!!</li>' +
|
||||
' </ul>'
|
||||
const html = `
|
||||
<b style='font-size: 20px;'>
|
||||
${this.$tl('p.reallyReleaseCurrentProject')}
|
||||
</b>
|
||||
<ul style='font-size: 20px;color:red;font-weight: bold;'>
|
||||
<li>this.$tl('p.willNotActuallyRequestNodeToDeleteProjectInfo')</b></li>
|
||||
<li>this.$tl('p.generallyUsedWhenServerCannotBeConnectedAndIsNoLongerNeeded')</li>
|
||||
<li>this.$tl('p.willProduceRedundantDataIfMisoperated')</li>
|
||||
</ul>
|
||||
`
|
||||
$confirm({
|
||||
title: '危险操作!!!',
|
||||
title: this.$tl('p.dangerousOperation'),
|
||||
zIndex: 1009,
|
||||
content: h('div', null, [h('p', { innerHTML: html }, null)]),
|
||||
okButtonProps: { type: 'primary', size: 'small', danger: true },
|
||||
cancelButtonProps: { type: 'primary' },
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
okText: this.$tl('p.confirm'),
|
||||
cancelText: this.$tl('p.cancel'),
|
||||
onOk: () => {
|
||||
return removeProject({
|
||||
nodeId: item.nodeId,
|
||||
|
@ -1,46 +1,46 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-space direction="vertical" style="width: 100%">
|
||||
<a-alert message="温馨提醒" type="info" show-icon>
|
||||
<a-alert :message="$tl('p.warmReminder')" type="info" show-icon>
|
||||
<template #description>
|
||||
<ul>
|
||||
<li>当前为节点分发的授权路径配置</li>
|
||||
<li>路径需要配置绝对路径</li>
|
||||
<li>{{ $tl('p.distributionAuthorizationPathConfig') }}</li>
|
||||
<li>{{ $tl('p.absolutePathRequired') }}</li>
|
||||
</ul>
|
||||
</template>
|
||||
</a-alert>
|
||||
<!-- <a-alert message=",不支持软链" type="info" /> -->
|
||||
|
||||
<a-form ref="editForm" :model="temp" :label-col="{ span: 6 }" :wrapper-col="{ span: 14 }" @finish="onSubmit">
|
||||
<a-form-item label="授权路径" name="outGiving">
|
||||
<template #help>用于创建节点分发项目、文件中心发布文件</template>
|
||||
<a-form-item :label="$tl('p.authorizationPath')" name="outGiving">
|
||||
<template #help>{{ $tl('p.usageForCreatingDistributionProjects') }}</template>
|
||||
<a-textarea
|
||||
v-model:value="temp.outGiving"
|
||||
:rows="5"
|
||||
style="resize: none"
|
||||
placeholder="请输入授权路径,回车支持输入多个路径,系统会自动过滤 ../ 路径、不允许输入根路径"
|
||||
:placeholder="$tl('p.inputAuthorizationPath')"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="静态目录" name="staticDir">
|
||||
<template #help>用于静态文件绑定和读取(不建议配置大目录,避免扫描消耗过多资源)</template>
|
||||
<a-form-item :label="$tl('p.staticDirectory')" name="staticDir">
|
||||
<template #help>{{ $tl('p.usageForStaticFileBindingAndReading') }}</template>
|
||||
<a-textarea
|
||||
v-model:value="temp.staticDir"
|
||||
:rows="5"
|
||||
style="resize: none"
|
||||
placeholder="请输入静态,回车支持输入多个路径,系统会自动过滤 ../ 路径、不允许输入根路径"
|
||||
:placeholder="$tl('p.inputStaticPaths')"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="远程下载安全HOST" name="allowRemoteDownloadHost">
|
||||
<template #help>用于下载远程文件来进行节点分发和文件上传</template>
|
||||
<a-form-item :label="$tl('p.remoteDownloadSecureHost')" name="allowRemoteDownloadHost">
|
||||
<template #help>{{ $tl('p.usageForDownloadingRemoteFiles') }}</template>
|
||||
<a-textarea
|
||||
v-model:value="temp.allowRemoteDownloadHost"
|
||||
:rows="5"
|
||||
style="resize: none"
|
||||
placeholder="请输入远程下载安全HOST,回车支持输入多个路径,示例 https://www.test.com 等"
|
||||
placeholder="{{$tl('p.inputRemoteDownloadSecureHosts')}}://www.test.com 等"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item :wrapper-col="{ span: 14, offset: 6 }">
|
||||
<a-button type="primary" html-type="submit" :disabled="submitAble">提交</a-button>
|
||||
<a-button type="primary" html-type="submit" :disabled="submitAble">{{ $tl('p.submit') }}</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-space>
|
||||
@ -67,6 +67,9 @@ export default {
|
||||
this.loadData()
|
||||
},
|
||||
methods: {
|
||||
$tl(key, ...args) {
|
||||
return this.$t(`pages.dispatch.whiteList.${key}`, ...args)
|
||||
},
|
||||
// load data
|
||||
loadData() {
|
||||
this.loading = true
|
||||
|
@ -35,7 +35,7 @@
|
||||
:type="systemNotificationData.level || 'info'"
|
||||
:closable="systemNotificationData.closable"
|
||||
banner
|
||||
:afterClose="notificationAfterClose"
|
||||
:after-close="notificationAfterClose"
|
||||
>
|
||||
<template #message> <div v-html="systemNotificationData.title"></div> </template>
|
||||
<template #description> <div v-html="systemNotificationData.content"></div> </template>
|
||||
@ -58,7 +58,11 @@
|
||||
>
|
||||
<router-view v-slot="{ Component, route }">
|
||||
<keep-alive :include="menuTabKeyList">
|
||||
<component :is="wrap(String(route.name), Component)" :key="String(route.name)" />
|
||||
<component
|
||||
:is="wrap(String(route.name), Component)"
|
||||
v-if="menuTabKeyList.length"
|
||||
:key="String(route.name)"
|
||||
/>
|
||||
</keep-alive>
|
||||
</router-view>
|
||||
</a-layout-content>
|
||||
@ -83,7 +87,7 @@ defineProps({
|
||||
required: true
|
||||
}
|
||||
})
|
||||
|
||||
const useUserStore2 = userStore()
|
||||
// 页面缓存对象
|
||||
const wrapperMap = shallowRef(new Map())
|
||||
// 组件套壳,动态添加name属性
|
||||
@ -113,6 +117,11 @@ const menuTabKeyList = computed(() => {
|
||||
watch(
|
||||
menuTabKeyList,
|
||||
(newKeys, oldKeys) => {
|
||||
if (!useUserStore2.getToken()) {
|
||||
// 登录登录会触发 tab 变化,这里不改变路由缓存。避免重新加载路由触发请求接口
|
||||
// 已经由 v-if="menuTabKeyList.length" 实现
|
||||
// return
|
||||
}
|
||||
// 获取已被删除的key
|
||||
oldKeys
|
||||
?.filter((key) => {
|
||||
|
@ -498,11 +498,11 @@
|
||||
</a-modal>
|
||||
<!-- 选择证书文件 -->
|
||||
<a-drawer
|
||||
v-if="certificateVisible"
|
||||
destroy-on-close
|
||||
:title="`选择证书文件`"
|
||||
placement="right"
|
||||
:open="certificateVisible"
|
||||
v-if="certificateVisible"
|
||||
width="85vw"
|
||||
:z-index="1009"
|
||||
:footer-style="{ textAlign: 'right' }"
|
||||
|
135
web-vue/src/pages/system/assets/machine/free-script.vue
Normal file
135
web-vue/src/pages/system/assets/machine/free-script.vue
Normal file
@ -0,0 +1,135 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-row :gutter="[16, 0]">
|
||||
<a-col :span="10">
|
||||
<a-form :model="temp">
|
||||
<a-form-item>
|
||||
<code-editor
|
||||
v-model:content="temp.content"
|
||||
height="calc(100vh - 50px - 30px - 100px)"
|
||||
:options="{ mode: 'shell', tabSize: 2 }"
|
||||
:show-tool="true"
|
||||
>
|
||||
<template #tool_before>
|
||||
<a-tooltip>
|
||||
<template #title>自由脚本是指直接在机器节点中执行任意脚本</template>
|
||||
帮助
|
||||
<QuestionCircleOutlined />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</code-editor>
|
||||
</a-form-item>
|
||||
<a-form-item label="执行路径" name="path">
|
||||
<a-input v-model:value="temp.path" placeholder="执行脚本的路径" />
|
||||
</a-form-item>
|
||||
<!-- <a-form-item :wrapper-col="{ span: 14, offset: 2 }">
|
||||
<a-space>
|
||||
<a-button type="primary" danger :disabled="submitAble" @click="onSubmit(true)">保存并重启</a-button>
|
||||
</a-space>
|
||||
</a-form-item> -->
|
||||
</a-form>
|
||||
</a-col>
|
||||
<a-col :span="14">
|
||||
<log-view2 ref="logView" height="calc(100vh - 50px - 30px)">
|
||||
<template #before>
|
||||
<a-space>
|
||||
<a-button
|
||||
type="primary"
|
||||
size="small"
|
||||
:loading="loading"
|
||||
:disabled="!temp.content"
|
||||
@click="onSubmit(false)"
|
||||
>执行</a-button
|
||||
>
|
||||
<a-switch
|
||||
v-model:checked="temp.appendTemplate"
|
||||
checked-children="追加脚本模板"
|
||||
un-checked-children="不追加脚本模板"
|
||||
/>
|
||||
</a-space>
|
||||
</template>
|
||||
</log-view2>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import codeEditor from '@/components/codeEditor'
|
||||
import LogView2 from '@/components/logView/index2'
|
||||
import { getWebSocketUrl } from '@/api/config'
|
||||
|
||||
const props = defineProps({
|
||||
machineId: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
|
||||
const socket = ref(null)
|
||||
const loading = ref(false)
|
||||
const logView = ref()
|
||||
const userStore_ = userStore()
|
||||
const temp = ref({
|
||||
appendTemplate: true,
|
||||
content: ''
|
||||
})
|
||||
|
||||
const socketUrl = computed(() => {
|
||||
return getWebSocketUrl(
|
||||
'/socket/free_script',
|
||||
`userId=${userStore_.getLongTermToken()}&machineId=${props.machineId}&nodeId=system&type=freeScript`
|
||||
)
|
||||
})
|
||||
|
||||
const conentScript = () => {
|
||||
socket.vlaue?.close()
|
||||
socket.vlaue = null
|
||||
const socket_ = new WebSocket(socketUrl.value)
|
||||
logView.value.clearLogCache()
|
||||
// 连接成功后
|
||||
socket_.onopen = () => {
|
||||
loading.value = true
|
||||
socket_.send(JSON.stringify(temp.value))
|
||||
}
|
||||
socket_.onmessage = (msg) => {
|
||||
logView.value.appendLine(msg.data)
|
||||
}
|
||||
socket_.onerror = (err) => {
|
||||
console.error(err)
|
||||
$notification.error({
|
||||
message: 'web socket 错误,请检查是否开启 ws 代理'
|
||||
})
|
||||
}
|
||||
socket_.onclose = (err) => {
|
||||
//当客户端收到服务端发送的关闭连接请求时,触发onclose事件
|
||||
console.error(err)
|
||||
loading.value = false
|
||||
$message.warning('会话已经关闭[free-script] ')
|
||||
// clearInterval(this.heart);
|
||||
}
|
||||
socket.value = socket_
|
||||
}
|
||||
|
||||
// console.log(socketUrl)
|
||||
|
||||
// const socketUrl = com
|
||||
|
||||
const onSubmit = () => {
|
||||
conentScript()
|
||||
}
|
||||
const close = () => {
|
||||
socket.vlaue?.close()
|
||||
socket.vlaue = null
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
|
||||
window.onbeforeunload = () => {
|
||||
close()
|
||||
}
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
close()
|
||||
})
|
||||
</script>
|
@ -28,6 +28,7 @@
|
||||
<a-tab-pane key="info" tab="基本信息"></a-tab-pane>
|
||||
<a-tab-pane key="cache" tab="缓存监控"></a-tab-pane>
|
||||
<a-tab-pane key="config" tab="系统配置"></a-tab-pane>
|
||||
<a-tab-pane key="freeScript" tab="自由脚本"></a-tab-pane>
|
||||
<a-tab-pane key="path-config" tab="授权配置"></a-tab-pane>
|
||||
<a-tab-pane key="upgrade" tab="在线升级"></a-tab-pane>
|
||||
<a-tab-pane key="log" tab="系统日志"></a-tab-pane>
|
||||
@ -43,6 +44,7 @@
|
||||
<cache v-if="current === 'cache'" :machine-id="machineId" />
|
||||
<log v-if="current === 'log'" :machine-id="machineId" />
|
||||
<config-file v-if="current === 'config'" :machine-id="machineId" />
|
||||
<freeScript v-if="current === 'freeScript'" :machine-id="machineId" />
|
||||
</div>
|
||||
</a-drawer>
|
||||
</template>
|
||||
@ -50,6 +52,7 @@
|
||||
<script>
|
||||
import { mapState } from 'pinia'
|
||||
import machineInfo from './machine-info'
|
||||
import freeScript from './free-script'
|
||||
import upgrade from '@/components/upgrade'
|
||||
import WhiteList from '@/pages/node/node-layout/system/white-list.vue'
|
||||
import Cache from '@/pages/node/node-layout/system/cache'
|
||||
@ -63,7 +66,8 @@ export default {
|
||||
WhiteList,
|
||||
Cache,
|
||||
ConfigFile,
|
||||
Log
|
||||
Log,
|
||||
freeScript
|
||||
},
|
||||
props: {
|
||||
machineId: {
|
||||
|
@ -148,10 +148,48 @@
|
||||
<!-- top 图表 -->
|
||||
<div id="top-chart" class="chart">loading...</div>
|
||||
</a-card>
|
||||
<a-card size="small" title="网络流量信息">
|
||||
<a-card size="small">
|
||||
<template #title>
|
||||
<a-space :size="4">
|
||||
<template #split>
|
||||
<a-divider type="vertical" />
|
||||
</template>
|
||||
网络流量信息
|
||||
<template v-if="monitorConfig?.network?.statExcludeNames">
|
||||
<span>
|
||||
排除:
|
||||
<a-tag v-for="item in monitorConfig?.network?.statExcludeNames?.split(',')">
|
||||
{{ item }}
|
||||
</a-tag>
|
||||
</span>
|
||||
</template>
|
||||
<template v-if="monitorConfig?.network?.statContainsOnlyNames">
|
||||
<span>
|
||||
仅统计:
|
||||
<a-tag v-for="item in monitorConfig?.network?.statContainsOnlyNames?.split(',')">
|
||||
{{ item }}
|
||||
</a-tag>
|
||||
</span>
|
||||
</template>
|
||||
<a-popover>
|
||||
<template #title>统计说明 </template>
|
||||
<template #content>
|
||||
<b>默认统计机器中除本地接口(环回或无硬件地址)网卡流量总和</b>
|
||||
<div>
|
||||
统计的网卡:
|
||||
<a-tag v-for="item in JSON.parse(machineInfo?.extendInfo || '{}')?.monitorIfsNames?.split(',')">
|
||||
{{ item }}
|
||||
</a-tag>
|
||||
</div>
|
||||
</template>
|
||||
<QuestionCircleOutlined />
|
||||
</a-popover>
|
||||
</a-space>
|
||||
</template>
|
||||
<template #extra>
|
||||
<a-button v-if="netHistoryChart" size="small" type="primary" @click="handleHistory('network-stat')">
|
||||
<AreaChartOutlined />历史监控图表
|
||||
<AreaChartOutlined />
|
||||
历史监控图表
|
||||
</a-button>
|
||||
</template>
|
||||
<!-- 网络流量图表 -->
|
||||
@ -462,7 +500,7 @@ import {
|
||||
machineNetworkInterfaces
|
||||
} from '@/api/node-stat'
|
||||
import { Empty } from 'ant-design-vue'
|
||||
import { statusMap } from '@/api/system/assets-machine'
|
||||
import { statusMap, machineMonitorConfig } from '@/api/system/assets-machine'
|
||||
import { useGuideStore } from '@/stores/guide'
|
||||
import { mapState } from 'pinia'
|
||||
export default {
|
||||
@ -736,7 +774,8 @@ export default {
|
||||
countdownTime: Date.now(),
|
||||
machineInfo: null,
|
||||
networkInterfaces: [],
|
||||
nodeMonitorLoadStatus: 0
|
||||
nodeMonitorLoadStatus: 0,
|
||||
monitorConfig: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -814,6 +853,12 @@ export default {
|
||||
//this.refreshInterval = this.getCacheNode("refreshInterval", this.refreshInterval);
|
||||
//
|
||||
this.pullNodeData()
|
||||
// 监控配置
|
||||
machineMonitorConfig({
|
||||
id: this.machineId
|
||||
}).then((res) => {
|
||||
this.monitorConfig = res.data || {}
|
||||
})
|
||||
},
|
||||
pullNodeData() {
|
||||
this.loadNodeTop()
|
||||
|
@ -37,7 +37,7 @@
|
||||
<a-form-item label="自动创建用户" name="autoCreteUser">
|
||||
<a-switch v-model:checked="dingtalk.autoCreteUser" checked-children="启用" un-checked-children="停用" />
|
||||
</a-form-item>
|
||||
<a-form-item label="权限组" name="permissionGroup" v-if="dingtalk.autoCreteUser">
|
||||
<a-form-item v-if="dingtalk.autoCreteUser" label="权限组" name="permissionGroup">
|
||||
<template #help>创建用户后自动关联上对应的权限组</template>
|
||||
<a-select
|
||||
v-model:value="dingtalk.permissionGroup"
|
||||
@ -88,7 +88,7 @@
|
||||
<a-form-item label="自动创建用户" name="autoCreteUser">
|
||||
<a-switch v-model:checked="feishu.autoCreteUser" checked-children="启用" un-checked-children="停用" />
|
||||
</a-form-item>
|
||||
<a-form-item label="权限组" name="permissionGroup" v-if="feishu.autoCreteUser">
|
||||
<a-form-item v-if="feishu.autoCreteUser" label="权限组" name="permissionGroup">
|
||||
<template #help>创建用户后自动关联上对应的权限组</template>
|
||||
<a-select
|
||||
v-model:value="feishu.permissionGroup"
|
||||
@ -163,7 +163,7 @@
|
||||
un-checked-children="停用"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="权限组" name="permissionGroup" v-if="wechat_enterprise.autoCreteUser">
|
||||
<a-form-item v-if="wechat_enterprise.autoCreteUser" label="权限组" name="permissionGroup">
|
||||
<template #help>创建用户后自动关联上对应的权限组</template>
|
||||
<a-select
|
||||
v-model:value="wechat_enterprise.permissionGroup"
|
||||
@ -227,7 +227,7 @@
|
||||
<a-form-item label="自动创建用户" name="autoCreteUser">
|
||||
<a-switch v-model:checked="maxkey.autoCreteUser" checked-children="启用" un-checked-children="停用" />
|
||||
</a-form-item>
|
||||
<a-form-item label="权限组" name="permissionGroup" v-if="maxkey.autoCreteUser">
|
||||
<a-form-item v-if="maxkey.autoCreteUser" label="权限组" name="permissionGroup">
|
||||
<template #help>创建用户后自动关联上对应的权限组</template>
|
||||
<a-select
|
||||
v-model:value="maxkey.permissionGroup"
|
||||
@ -279,7 +279,7 @@
|
||||
<a-form-item label="自动创建用户" name="autoCreteUser">
|
||||
<a-switch v-model:checked="gitee.autoCreteUser" checked-children="启用" un-checked-children="停用" />
|
||||
</a-form-item>
|
||||
<a-form-item label="权限组" name="permissionGroup" v-if="gitee.autoCreteUser">
|
||||
<a-form-item v-if="gitee.autoCreteUser" label="权限组" name="permissionGroup">
|
||||
<template #help>创建用户后自动关联上对应的权限组</template>
|
||||
<a-select
|
||||
v-model:value="gitee.permissionGroup"
|
||||
@ -340,7 +340,7 @@
|
||||
<a-form-item label="自动创建用户" name="autoCreteUser">
|
||||
<a-switch v-model:checked="mygitlab.autoCreteUser" checked-children="启用" un-checked-children="停用" />
|
||||
</a-form-item>
|
||||
<a-form-item label="权限组" name="permissionGroup" v-if="mygitlab.autoCreteUser">
|
||||
<a-form-item v-if="mygitlab.autoCreteUser" label="权限组" name="permissionGroup">
|
||||
<template #help>创建用户后自动关联上对应的权限组</template>
|
||||
<a-select
|
||||
v-model:value="mygitlab.permissionGroup"
|
||||
@ -394,7 +394,7 @@
|
||||
<a-form-item label="自动创建用户" name="autoCreteUser">
|
||||
<a-switch v-model:checked="github.autoCreteUser" checked-children="启用" un-checked-children="停用" />
|
||||
</a-form-item>
|
||||
<a-form-item label="权限组" name="permissionGroup" v-if="github.autoCreteUser">
|
||||
<a-form-item v-if="github.autoCreteUser" label="权限组" name="permissionGroup">
|
||||
<template #help>创建用户后自动关联上对应的权限组</template>
|
||||
<a-select
|
||||
v-model:value="github.permissionGroup"
|
||||
|
@ -12,8 +12,8 @@
|
||||
:columns="taskColumns"
|
||||
bordered
|
||||
:data-source="taskList"
|
||||
@refresh="refresh"
|
||||
:pagination="false"
|
||||
@refresh="refresh"
|
||||
>
|
||||
<!-- <template #title>
|
||||
<a-button size="small" type="primary" @click="refresh"><ReloadOutlined /></a-button>
|
||||
|
@ -73,13 +73,13 @@
|
||||
</a-form-item>
|
||||
<template v-if="Object.keys(pingReulst).length">
|
||||
<a-form-item label="结果" name="result">
|
||||
<a-tag color="green" v-if="pingReulst.ping">成功</a-tag>
|
||||
<a-tag color="red" v-else>失败</a-tag>
|
||||
<a-tag v-if="pingReulst.ping" color="green">成功</a-tag>
|
||||
<a-tag v-else color="red">失败</a-tag>
|
||||
</a-form-item>
|
||||
<a-form-item label="类型" name="labels">
|
||||
<a-tag v-for="item in pingReulst.labels">{{ item }}</a-tag>
|
||||
</a-form-item>
|
||||
<a-form-item label="原始IP" name="originalIP" v-if="pingReulst.originalIP">
|
||||
<a-form-item v-if="pingReulst.originalIP" label="原始IP" name="originalIP">
|
||||
{{ pingReulst.originalIP }}
|
||||
</a-form-item>
|
||||
</template>
|
||||
@ -141,13 +141,13 @@
|
||||
</a-form-item>
|
||||
<template v-if="Object.keys(telnetReulst).length">
|
||||
<a-form-item label="结果" name="result">
|
||||
<a-tag color="green" v-if="telnetReulst.open">成功</a-tag>
|
||||
<a-tag color="red" v-else>失败</a-tag>
|
||||
<a-tag v-if="telnetReulst.open" color="green">成功</a-tag>
|
||||
<a-tag v-else color="red">失败</a-tag>
|
||||
</a-form-item>
|
||||
<a-form-item label="类型" name="labels">
|
||||
<a-tag v-for="item in telnetReulst.labels">{{ item }}</a-tag>
|
||||
</a-form-item>
|
||||
<a-form-item label="原始IP" name="originalIP" v-if="telnetReulst.originalIP">
|
||||
<a-form-item v-if="telnetReulst.originalIP" label="原始IP" name="originalIP">
|
||||
{{ telnetReulst.originalIP }}
|
||||
</a-form-item>
|
||||
</template>
|
||||
|
Loading…
Reference in New Issue
Block a user