pageResult = userLoginLogServer.listPage(request);
+ return JsonMessage.success("", pageResult);
+ }
+}
diff --git a/modules/server/src/main/java/io/jpom/func/user/model/UserLoginLogModel.java b/modules/server/src/main/java/io/jpom/func/user/model/UserLoginLogModel.java
new file mode 100644
index 000000000..662add597
--- /dev/null
+++ b/modules/server/src/main/java/io/jpom/func/user/model/UserLoginLogModel.java
@@ -0,0 +1,77 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Code Technology Studio
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+package io.jpom.func.user.model;
+
+import io.jpom.model.BaseUserModifyDbModel;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import top.jpom.h2db.TableName;
+
+/**
+ * @author bwcx_jzy
+ * @since 2023/3/9
+ */
+@EqualsAndHashCode(callSuper = true)
+@TableName(value = "USER_LOGIN_LOG", name = "用户登录日志")
+@Data
+@NoArgsConstructor
+public class UserLoginLogModel extends BaseUserModifyDbModel {
+
+ /**
+ * 操作ip
+ */
+ private String ip;
+
+ /**
+ * 用户名称
+ */
+ private String username;
+
+ /**
+ * 浏览器标识
+ */
+ private String userAgent;
+
+ /**
+ * 是否使用 mfa
+ */
+ private Boolean useMfa;
+
+ /**
+ * 是否成功
+ */
+ private Boolean success;
+
+ /**
+ * 错误原因
+ *
+ * 0 正常登录
+ * 1 密码错误
+ * 2 被锁定
+ * 3 续期
+ * 4 账号被禁用
+ * 5 登录成功,但是需要 mfa 验证
+ */
+ private Integer operateCode;
+}
diff --git a/modules/server/src/main/java/io/jpom/func/user/server/UserLoginLogServer.java b/modules/server/src/main/java/io/jpom/func/user/server/UserLoginLogServer.java
new file mode 100644
index 000000000..1327f237d
--- /dev/null
+++ b/modules/server/src/main/java/io/jpom/func/user/server/UserLoginLogServer.java
@@ -0,0 +1,111 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Code Technology Studio
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+package io.jpom.func.user.server;
+
+import cn.hutool.core.util.CharsetUtil;
+import cn.hutool.extra.servlet.ServletUtil;
+import cn.hutool.http.Header;
+import io.jpom.func.user.model.UserLoginLogModel;
+import io.jpom.model.user.UserModel;
+import io.jpom.service.h2db.BaseDbService;
+import org.springframework.stereotype.Service;
+import top.jpom.model.PageResultDto;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Map;
+
+/**
+ * @author bwcx_jzy
+ * @since 2023/3/9
+ */
+@Service
+public class UserLoginLogServer extends BaseDbService {
+
+
+ /**
+ * 查询指定用户的登录日志
+ *
+ * @param request 请求信息
+ * @param userId 用户id
+ * @return page
+ */
+ public PageResultDto listPageByUserId(HttpServletRequest request, String userId) {
+ Map paramMap = ServletUtil.getParamMap(request);
+ paramMap.put("modifyUser", userId);
+ return super.listPage(paramMap);
+ }
+
+ /**
+ * 记录登录日志
+ *
+ * @param userModel 用户
+ * @param success 是否成功
+ * @param useMfa 是否使用 mfa
+ * @param request 请求信息
+ */
+ public void log(UserModel userModel, boolean success, boolean useMfa, int operateCode, HttpServletRequest request) {
+ UserLoginLogModel userLoginLogModel = new UserLoginLogModel();
+ userLoginLogModel.setModifyUser(userModel.getId());
+ userLoginLogModel.setUsername(userModel.getName());
+ userLoginLogModel.setSuccess(success);
+ userLoginLogModel.setUseMfa(useMfa);
+ userLoginLogModel.setOperateCode(operateCode);
+ userLoginLogModel.setIp(ServletUtil.getClientIP(request));
+ userLoginLogModel.setUserAgent(ServletUtil.getHeader(request, Header.USER_AGENT.getValue(), CharsetUtil.CHARSET_UTF_8));
+ this.insert(userLoginLogModel);
+ }
+
+ /**
+ * 记录登录日志
+ *
+ * @param userModel 用户
+ * @param useMfa 是否使用 mfa
+ * @param request 请求信息
+ */
+ public void success(UserModel userModel, boolean useMfa, HttpServletRequest request) {
+ this.success(userModel, 0, useMfa, request);
+ }
+
+ /**
+ * 记录登录日志
+ *
+ * @param userModel 用户
+ * @param useMfa 是否使用 mfa
+ * @param request 请求信息
+ */
+ public void success(UserModel userModel, int code, boolean useMfa, HttpServletRequest request) {
+ this.log(userModel, true, useMfa, code, request);
+ }
+
+ /**
+ * 记录登录日志
+ *
+ * @param userModel 用户
+ * @param useMfa 是否使用 mfa
+ * @param code 错误码
+ * @param request 请求信息
+ */
+ public void fail(UserModel userModel, int code, boolean useMfa, HttpServletRequest request) {
+ this.log(userModel, false, useMfa, code, request);
+ }
+}
diff --git a/modules/server/src/main/java/io/jpom/model/log/UserOperateLogV1.java b/modules/server/src/main/java/io/jpom/model/log/UserOperateLogV1.java
index 843bcda5f..6f3b78ef1 100644
--- a/modules/server/src/main/java/io/jpom/model/log/UserOperateLogV1.java
+++ b/modules/server/src/main/java/io/jpom/model/log/UserOperateLogV1.java
@@ -61,12 +61,6 @@ public class UserOperateLogV1 extends BaseWorkspaceModel {
* 完整消息
*/
private String resultMsg;
- /**
- * 操作id
- * 用于socket 回话回调更新
- */
- @Deprecated
- private String reqId;
/**
* 请求参数
*/
@@ -86,10 +80,10 @@ public class UserOperateLogV1 extends BaseWorkspaceModel {
private String classFeature;
private String methodFeature;
+ /**
+ * 工作空间名称
+ */
+ private String workspaceName;
- @Override
- public void setId(String id) {
- super.setId(id);
- this.setReqId(id);
- }
+ private String username;
}
diff --git a/modules/server/src/main/java/io/jpom/permission/ClassFeature.java b/modules/server/src/main/java/io/jpom/permission/ClassFeature.java
index c3bcbe903..a3940dde9 100644
--- a/modules/server/src/main/java/io/jpom/permission/ClassFeature.java
+++ b/modules/server/src/main/java/io/jpom/permission/ClassFeature.java
@@ -22,6 +22,10 @@
*/
package io.jpom.permission;
+import io.jpom.func.assets.server.MachineDockerServer;
+import io.jpom.func.assets.server.MachineNodeServer;
+import io.jpom.func.assets.server.MachineSshServer;
+import io.jpom.func.user.server.UserLoginLogServer;
import io.jpom.service.dblog.*;
import io.jpom.service.docker.DockerInfoService;
import io.jpom.service.docker.DockerSwarmInfoService;
@@ -84,14 +88,15 @@ public enum ClassFeature {
BUILD_REPOSITORY("仓库信息", RepositoryService.class),
USER("用户管理", UserService.class),
USER_LOG("操作日志", DbUserOperateLogService.class),
+ USER_LOGIN_LOG("登录日志", UserLoginLogServer.class),
USER_PERMISSION_GROUP("权限分组", UserPermissionGroupServer.class),
SYSTEM_EMAIL("邮箱配置"),
SYSTEM_CACHE("系统缓存"),
SYSTEM_LOG("系统日志"),
SYSTEM_UPGRADE("在线升级"),
- SYSTEM_ASSETS_MACHINE("机器资产管理"),
- SYSTEM_ASSETS_MACHINE_SSH("SSH资产管理"),
- SYSTEM_ASSETS_MACHINE_DOCKER("DOCKER资产管理"),
+ SYSTEM_ASSETS_MACHINE("机器资产管理", MachineNodeServer.class),
+ SYSTEM_ASSETS_MACHINE_SSH("SSH资产管理", MachineSshServer.class),
+ SYSTEM_ASSETS_MACHINE_DOCKER("DOCKER资产管理", MachineDockerServer.class),
SYSTEM_CONFIG("服务端系统配置"),
SYSTEM_EXT_CONFIG("系统配置目录"),
SYSTEM_CONFIG_IP("系统配置IP白名单"),
diff --git a/modules/server/src/main/java/io/jpom/permission/Feature.java b/modules/server/src/main/java/io/jpom/permission/Feature.java
index c256fa05d..fbbb4c6ad 100644
--- a/modules/server/src/main/java/io/jpom/permission/Feature.java
+++ b/modules/server/src/main/java/io/jpom/permission/Feature.java
@@ -49,13 +49,6 @@ public @interface Feature {
*/
MethodFeature method() default MethodFeature.NULL;
- /**
- * 只记录哪些 状态码
- *
- * @return code
- */
- int[] resultCode() default {};
-
/**
* 是否记录响应 日志
*
diff --git a/modules/server/src/main/java/io/jpom/service/dblog/DbUserOperateLogService.java b/modules/server/src/main/java/io/jpom/service/dblog/DbUserOperateLogService.java
index ae8488fb0..e9bc375fa 100644
--- a/modules/server/src/main/java/io/jpom/service/dblog/DbUserOperateLogService.java
+++ b/modules/server/src/main/java/io/jpom/service/dblog/DbUserOperateLogService.java
@@ -80,6 +80,19 @@ public class DbUserOperateLogService extends BaseWorkspaceService listPageByUserId(HttpServletRequest request, String userId) {
+ Map paramMap = ServletUtil.getParamMap(request);
+ paramMap.put("userId", userId);
+ return super.listPage(paramMap);
+ }
+
/**
* 根据 数据ID 和 节点ID 查询相关数据名称
*
@@ -247,6 +260,19 @@ public class DbUserOperateLogService extends BaseWorkspaceService {
+ // 更新用户名和工作空间名
+ try {
+ UserOperateLogV1 update = new UserOperateLogV1();
+ update.setId(userOperateLogV1.getId());
+ UserModel userModel = userService.getByKey(userOperateLogV1.getUserId());
+ Optional.ofNullable(userModel).ifPresent(userModel1 -> update.setUsername(userModel1.getName()));
+ WorkspaceModel workspaceModel = workspaceService.getByKey(userOperateLogV1.getWorkspaceId());
+ Optional.ofNullable(workspaceModel).ifPresent(workspaceModel1 -> update.setWorkspaceName(workspaceModel1.getName()));
+ this.update(update);
+ } catch (Exception e) {
+ log.error("更新操作日志失败", e);
+ }
+ // 检查操作监控
try {
Map monitor = this.checkMonitor(userOperateLogV1, cacheInfo);
if (monitor != null) {
diff --git a/modules/server/src/main/java/io/jpom/service/user/TriggerTokenLogServer.java b/modules/server/src/main/java/io/jpom/service/user/TriggerTokenLogServer.java
index 336896139..2f0750453 100644
--- a/modules/server/src/main/java/io/jpom/service/user/TriggerTokenLogServer.java
+++ b/modules/server/src/main/java/io/jpom/service/user/TriggerTokenLogServer.java
@@ -132,7 +132,7 @@ public class TriggerTokenLogServer extends BaseDbService im
* @param userId 用户ID
* @return token
*/
- public String createToken(String type, String dataId, String userId) {
+ private String createToken(String type, String dataId, String userId) {
TriggerTokenLogBean trigger = new TriggerTokenLogBean();
String uuid = IdUtil.fastSimpleUUID();
trigger.setId(uuid);
diff --git a/modules/server/src/main/java/io/jpom/system/init/OperateLogController.java b/modules/server/src/main/java/io/jpom/system/init/OperateLogController.java
index 862e56d29..703de41fe 100644
--- a/modules/server/src/main/java/io/jpom/system/init/OperateLogController.java
+++ b/modules/server/src/main/java/io/jpom/system/init/OperateLogController.java
@@ -24,7 +24,6 @@ package io.jpom.system.init;
import cn.hutool.core.date.SystemClock;
import cn.hutool.core.exceptions.ExceptionUtil;
-import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.Entity;
@@ -109,10 +108,8 @@ public class OperateLogController implements AopLogInterface {
cacheInfo.setClassFeature(classFeature);
cacheInfo.setMethodFeature(methodFeature);
cacheInfo.setOptTime(SystemClock.now());
- cacheInfo.setResultCode(feature.resultCode());
cacheInfo.setLogResponse(feature.logResponse());
//
-
return cacheInfo;
}
@@ -235,11 +232,6 @@ public class OperateLogController implements AopLogInterface {
try {
JsonMessage> jsonMessage = JSONObject.parseObject(json, JsonMessage.class);
int code = jsonMessage.getCode();
- int[] resultCode = cacheInfo.getResultCode();
- if (ArrayUtil.isNotEmpty(resultCode) && !ArrayUtil.contains(resultCode, code)) {
- // 忽略
- return;
- }
userOperateLogV1.setOptStatus(code);
} catch (Exception ignored) {
}
@@ -301,7 +293,6 @@ public class OperateLogController implements AopLogInterface {
private String dataId;
private String userAgent;
private String reqData;
- private int[] resultCode;
private Boolean logResponse;
/**
* 操作到数据到名称相关 map
diff --git a/modules/server/src/main/resources/menus/index.json b/modules/server/src/main/resources/menus/index.json
index bb306cba0..8d8c15ac4 100644
--- a/modules/server/src/main/resources/menus/index.json
+++ b/modules/server/src/main/resources/menus/index.json
@@ -136,5 +136,16 @@
"title": "操作监控"
}
]
+ },
+ {
+ "title": "在线工具",
+ "icon_v3": "tool",
+ "id": "tools",
+ "childs": [
+ {
+ "id": "cronTools",
+ "title": "Cron表达式"
+ }
+ ]
}
]
diff --git a/modules/server/src/main/resources/menus/system.json b/modules/server/src/main/resources/menus/system.json
index 5ace8d4e8..c822abfe9 100644
--- a/modules/server/src/main/resources/menus/system.json
+++ b/modules/server/src/main/resources/menus/system.json
@@ -57,6 +57,11 @@
"id": "user_log",
"title": "操作日志",
"role": "system"
+ },
+ {
+ "id": "user_login_log",
+ "title": "登录日志",
+ "role": "system"
}
]
},
diff --git a/modules/server/src/main/resources/sql-view/alter.all.v1.3.csv b/modules/server/src/main/resources/sql-view/alter.all.v1.3.csv
index 27670bf7f..107b083dd 100644
--- a/modules/server/src/main/resources/sql-view/alter.all.v1.3.csv
+++ b/modules/server/src/main/resources/sql-view/alter.all.v1.3.csv
@@ -12,4 +12,7 @@ DROP,DOCKER_SWARM_INFO,status,
DROP,DOCKER_SWARM_INFO,failureMsg,
DROP,DOCKER_INFO,status
DROP,DOCKER_INFO,failureMsg
-ADD,MACHINE_NODE_INFO,transportEncryption,TINYINT,,,传输加密方式 0 不加密 1 BASE64 2 AES
+DROP,USEROPERATELOGV1,reqId
+ADD,USEROPERATELOGV1,workspaceName,String,50,,工作空间名
+ADD,USEROPERATELOGV1,username,String,50,,用户名
+ADD,MACHINE_NODE_INFO,transportEncryption,TINYINT,,,传输加密方式 0 不加密 1 BASE64 2 AES
\ No newline at end of file
diff --git a/modules/server/src/main/resources/sql-view/table.all.v1.0.csv b/modules/server/src/main/resources/sql-view/table.all.v1.0.csv
index 1dd0c5ac4..dbea27ef7 100644
--- a/modules/server/src/main/resources/sql-view/table.all.v1.0.csv
+++ b/modules/server/src/main/resources/sql-view/table.all.v1.0.csv
@@ -307,7 +307,6 @@ OUT_GIVING,status,Integer,,0,false,false,状态{0: 未分发; 1: 分发中; 2:
OUT_GIVING,secondaryDirectory,String,200,,false,false,二级目录,
OUT_GIVING,uploadCloseFirst,TINYINT,,0,false,false,是否清空旧包发布,
USEROPERATELOGV1,id,String,50,,true,true,id,操作日志
-USEROPERATELOGV1,reqId,String,50,,false,false,请求ID,
USEROPERATELOGV1,ip,String,80,,false,false,客户端IP地址,
USEROPERATELOGV1,userId,String,30,,false,false,操作的用户ID,
USEROPERATELOGV1,resultMsg,TEXT,,,false,false,操作的结果信息,
diff --git a/modules/server/src/main/resources/sql-view/table.all.v1.1.csv b/modules/server/src/main/resources/sql-view/table.all.v1.1.csv
index 569aa9753..dc0a73dda 100644
--- a/modules/server/src/main/resources/sql-view/table.all.v1.1.csv
+++ b/modules/server/src/main/resources/sql-view/table.all.v1.1.csv
@@ -84,3 +84,13 @@ MACHINE_DOCKER_INFO,registryUsername,String,255,,false,false,仓库账号,
MACHINE_DOCKER_INFO,registryPassword,String,255,,false,false,仓库密码,
MACHINE_DOCKER_INFO,registryEmail,String,255,,false,false,仓库邮箱,
MACHINE_DOCKER_INFO,registryUrl,String,255,,false,false,仓库地址,
+USER_LOGIN_LOG,id,String,50,,true,true,id,用户登录日志
+USER_LOGIN_LOG,createTimeMillis,Long,,,false,false,数据创建时间,
+USER_LOGIN_LOG,modifyTimeMillis,Long,,,false,false,数据修改时间,
+USER_LOGIN_LOG,modifyUser,String,50,,false,false,修改人,
+USER_LOGIN_LOG,ip,String,80,,false,false,客户端IP地址,
+USER_LOGIN_LOG,userAgent,TEXT,,,false,false,浏览器标识,
+USER_LOGIN_LOG,useMfa,TINYINT,,,false,false,是否使用 mfa,
+USER_LOGIN_LOG,success,TINYINT,,,false,false,是否登录成功,
+USER_LOGIN_LOG,operateCode,TINYINT,,,false,false,操作状态码(备注码),
+USER_LOGIN_LOG,username,String,50,,false,false,昵称,
diff --git a/modules/server/src/test/java/TestCron.java b/modules/server/src/test/java/TestCron.java
index 58139f61c..e4fda068d 100644
--- a/modules/server/src/test/java/TestCron.java
+++ b/modules/server/src/test/java/TestCron.java
@@ -20,7 +20,17 @@
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+import cn.hutool.core.date.DatePattern;
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
import cn.hutool.cron.CronUtil;
+import cn.hutool.cron.pattern.CronPattern;
+import cn.hutool.cron.pattern.CronPatternUtil;
+import org.junit.Test;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
/**
* Created by jiangzeyin on 2019/3/4.
@@ -36,4 +46,25 @@ public class TestCron {
CronUtil.restart();
// System.out.println(JpomApplicationEvent.getPid());
}
+
+ @Test
+ public void test() {
+ String cron = "0 0 23 ? * 5 ";
+
+ CronPattern cronPattern = CronPattern.of(cron);
+
+// Date date = CronPatternUtil.nextDateAfter(cronPattern, DateUtil.offsetDay(DateTime.now(), -1), false);
+
+ List dateList = CronPatternUtil.matchedDates(cron, DateUtil.offsetDay(DateTime.now(), -1), 10, true);
+ for (Date date1 : dateList) {
+ System.out.println(DateUtil.format(date1, DatePattern.NORM_DATETIME_FORMAT));
+ }
+
+ }
+
+ @Test
+ public void test2() {
+ Calendar calendar = DateTime.now().toCalendar();
+ System.out.println(calendar.get(Calendar.DAY_OF_WEEK) - 1);
+ }
}
diff --git a/modules/storage-module/pom.xml b/modules/storage-module/pom.xml
index 931c7c28a..aa3602615 100644
--- a/modules/storage-module/pom.xml
+++ b/modules/storage-module/pom.xml
@@ -29,7 +29,7 @@
jpom-parent
io.jpom
- 2.10.28
+ 2.10.29
../../pom.xml
pom
@@ -39,7 +39,7 @@
storage-module-mysql
4.0.0
- 2.10.28
+ 2.10.29
io.jpom.storage-module
jpom-storage-module-parent
Jpom storage module
diff --git a/modules/storage-module/storage-module-common/pom.xml b/modules/storage-module/storage-module-common/pom.xml
index a68209a12..fe3b2018b 100644
--- a/modules/storage-module/storage-module-common/pom.xml
+++ b/modules/storage-module/storage-module-common/pom.xml
@@ -30,7 +30,7 @@
io.jpom.storage-module
jpom-storage-module-parent
- 2.10.28
+ 2.10.29
../pom.xml
diff --git a/modules/storage-module/storage-module-h2/pom.xml b/modules/storage-module/storage-module-h2/pom.xml
index 99b890637..a64a6ed5a 100644
--- a/modules/storage-module/storage-module-h2/pom.xml
+++ b/modules/storage-module/storage-module-h2/pom.xml
@@ -30,7 +30,7 @@
io.jpom.storage-module
jpom-storage-module-parent
- 2.10.28
+ 2.10.29
../pom.xml
diff --git a/modules/storage-module/storage-module-mysql/pom.xml b/modules/storage-module/storage-module-mysql/pom.xml
index 03cfa1fd3..50c0facb7 100644
--- a/modules/storage-module/storage-module-mysql/pom.xml
+++ b/modules/storage-module/storage-module-mysql/pom.xml
@@ -30,7 +30,7 @@
io.jpom.storage-module
jpom-storage-module-parent
- 2.10.28
+ 2.10.29
../pom.xml
diff --git a/modules/sub-plugin/docker-cli/pom.xml b/modules/sub-plugin/docker-cli/pom.xml
index 60e526878..fa5ae19ca 100644
--- a/modules/sub-plugin/docker-cli/pom.xml
+++ b/modules/sub-plugin/docker-cli/pom.xml
@@ -29,7 +29,7 @@
jpom-plugins-parent
io.jpom.plugins
- 2.10.28
+ 2.10.29
../pom.xml
4.0.0
diff --git a/modules/sub-plugin/email/pom.xml b/modules/sub-plugin/email/pom.xml
index 813f983fe..207c9bb77 100644
--- a/modules/sub-plugin/email/pom.xml
+++ b/modules/sub-plugin/email/pom.xml
@@ -29,7 +29,7 @@
jpom-plugins-parent
io.jpom.plugins
- 2.10.28
+ 2.10.29
../pom.xml
4.0.0
diff --git a/modules/sub-plugin/git-clone/pom.xml b/modules/sub-plugin/git-clone/pom.xml
index 94b0daa61..33bd4ac94 100644
--- a/modules/sub-plugin/git-clone/pom.xml
+++ b/modules/sub-plugin/git-clone/pom.xml
@@ -29,7 +29,7 @@
jpom-plugins-parent
io.jpom.plugins
- 2.10.28
+ 2.10.29
../pom.xml
4.0.0
diff --git a/modules/sub-plugin/pom.xml b/modules/sub-plugin/pom.xml
index 84200a21a..4fa3ccbdb 100644
--- a/modules/sub-plugin/pom.xml
+++ b/modules/sub-plugin/pom.xml
@@ -29,7 +29,7 @@
jpom-parent
io.jpom
- 2.10.28
+ 2.10.29
../../pom.xml
pom
@@ -42,7 +42,7 @@
encrypt
4.0.0
- 2.10.28
+ 2.10.29
io.jpom.plugins
jpom-plugins-parent
Jpom Plugins
diff --git a/modules/sub-plugin/svn-clone/pom.xml b/modules/sub-plugin/svn-clone/pom.xml
index dfde96d74..4a7b2e834 100644
--- a/modules/sub-plugin/svn-clone/pom.xml
+++ b/modules/sub-plugin/svn-clone/pom.xml
@@ -29,7 +29,7 @@
jpom-plugins-parent
io.jpom.plugins
- 2.10.28
+ 2.10.29
../pom.xml
4.0.0
diff --git a/modules/sub-plugin/webhook/pom.xml b/modules/sub-plugin/webhook/pom.xml
index dc2e307aa..aaa2a5e60 100644
--- a/modules/sub-plugin/webhook/pom.xml
+++ b/modules/sub-plugin/webhook/pom.xml
@@ -29,7 +29,7 @@
jpom-plugins-parent
io.jpom.plugins
- 2.10.28
+ 2.10.29
../pom.xml
4.0.0
diff --git a/modules/updater/pom.xml b/modules/updater/pom.xml
index 4abc1efab..fcb2dc2a4 100644
--- a/modules/updater/pom.xml
+++ b/modules/updater/pom.xml
@@ -29,7 +29,7 @@
jpom-parent
io.jpom
- 2.10.28
+ 2.10.29
../../pom.xml
4.0.0
diff --git a/pom.xml b/pom.xml
index f07b1759d..1de62fc46 100644
--- a/pom.xml
+++ b/pom.xml
@@ -50,7 +50,7 @@
简而轻的低侵入式在线构建、自动部署、日常运维、项目监控软件
2017
- 2.10.28
+ 2.10.29
https://gitee.com/dromara/Jpom
UTF-8
diff --git a/script/docker.sh b/script/docker.sh
index 256528ea0..a35407443 100644
--- a/script/docker.sh
+++ b/script/docker.sh
@@ -31,12 +31,12 @@
# docker buildx create --use
# 服务端
-docker buildx build --platform linux/amd64,linux/arm64 -t jpomdocker/jpom:2.10.28 -t jpomdocker/jpom:latest -f ./modules/server/DockerfileRelease --push .
+docker buildx build --platform linux/amd64,linux/arm64 -t jpomdocker/jpom:2.10.29 -t jpomdocker/jpom:latest -f ./modules/server/DockerfileRelease --push .
#
#docker buildx build --platform linux/amd64,linux/arm64 -t jpomdocker/jpom:latest -f ./modules/server/DockerfileRelease --push .
# docker logs --tail="100" jpom-server
-# docker run -d -p 2122:2122 --name jpom-server -v /etc/localtime:/etc/localtime:ro -v jpom-server-vol:/usr/local/jpom-server jpomdocker/jpom:mac-arm-2.10.28
+# docker run -d -p 2122:2122 --name jpom-server -v /etc/localtime:/etc/localtime:ro -v jpom-server-vol:/usr/local/jpom-server jpomdocker/jpom:mac-arm-2.10.29
# docker run -d -p 2122:2122 --name jpom-server -v D:/home/jpom-server/logs:/usr/local/jpom-server/logs -v D:/home/jpom-server/data:/usr/local/jpom-server/data -v D:/home/jpom-server/conf:/usr/local/jpom-server/conf jpomdocker/jpom
# docker stop jpom-server
# docker rm jpom-server
diff --git a/script/release-sha1sum.sh b/script/release-sha1sum.sh
index 3cb87228b..4fa76d90b 100644
--- a/script/release-sha1sum.sh
+++ b/script/release-sha1sum.sh
@@ -24,7 +24,7 @@
# 版本
-jpom_version=2.10.28
+jpom_version=2.10.29
#Mirror_Host=download.fastgit.org
#Mirror_Host=hub.fastgit.xyz
diff --git a/web-vue/package.json b/web-vue/package.json
index f80eba8e3..d09ff5eea 100644
--- a/web-vue/package.json
+++ b/web-vue/package.json
@@ -1,6 +1,6 @@
{
"name": "jpom-vue",
- "version": "2.10.28",
+ "version": "2.10.29",
"private": true,
"scripts": {
"serve": "vue-cli-service --max-old-space-size=900 serve --mode dev",
diff --git a/web-vue/src/api/tools.js b/web-vue/src/api/tools.js
new file mode 100644
index 000000000..0ed57f760
--- /dev/null
+++ b/web-vue/src/api/tools.js
@@ -0,0 +1,13 @@
+import axios from "./config";
+
+/**
+ *
+ * @param data
+ */
+export function cronTools(data) {
+ return axios({
+ url: "/tools/cron",
+ method: "get",
+ params: data,
+ });
+}
diff --git a/web-vue/src/api/user/user-login-log.js b/web-vue/src/api/user/user-login-log.js
new file mode 100644
index 000000000..fa4faf507
--- /dev/null
+++ b/web-vue/src/api/user/user-login-log.js
@@ -0,0 +1,18 @@
+import axios from "../config";
+
+export function userLoginLgin(params) {
+ return axios({
+ url: "/user/login-log/list-data",
+ method: "post",
+ data: params,
+ });
+}
+
+export const operateCodeMap = {
+ 0: "正常登录",
+ 1: "密码错误",
+ 2: "账号被锁定",
+ 3: "自动续期",
+ 4: "账号被禁用",
+ 5: "登录成功,需要验证 MFA",
+};
diff --git a/web-vue/src/api/user/user.js b/web-vue/src/api/user/user.js
index f3b07f9c5..f8f6fa51f 100644
--- a/web-vue/src/api/user/user.js
+++ b/web-vue/src/api/user/user.js
@@ -238,3 +238,19 @@ export function demoInfo() {
params: {},
});
}
+
+export function listLoginLog(params) {
+ return axios({
+ url: "/user/list-login-log-data",
+ method: "post",
+ data: params,
+ });
+}
+
+export function listOperaterLog(params) {
+ return axios({
+ url: "/user/list-operate-log-data",
+ method: "post",
+ data: params,
+ });
+}
diff --git a/web-vue/src/pages/build/history.vue b/web-vue/src/pages/build/history.vue
index 83364b5ea..178718f82 100644
--- a/web-vue/src/pages/build/history.vue
+++ b/web-vue/src/pages/build/history.vue
@@ -128,9 +128,9 @@ export default {
buildLogVisible: false,
tableSelections: [],
columns: [
- { title: "构建名称", dataIndex: "buildName", /*width: 120,*/ ellipsis: true, scopedSlots: { customRender: "tooltip" } },
- { title: "构建 ID", dataIndex: "buildNumberId", width: 90, align: "center", ellipsis: true, scopedSlots: { customRender: "buildNumberId" } },
- { title: "备注", dataIndex: "buildRemark", /*width: 120,*/ ellipsis: true, scopedSlots: { customRender: "tooltip" } },
+ { title: "构建名称", dataIndex: "buildName", width: 120, ellipsis: true, scopedSlots: { customRender: "tooltip" } },
+ { title: "构建 ID", dataIndex: "buildNumberId", width: "90px", align: "center", ellipsis: true, scopedSlots: { customRender: "buildNumberId" } },
+ { title: "备注", dataIndex: "buildRemark", width: 120, ellipsis: true, scopedSlots: { customRender: "tooltip" } },
{ title: "状态", dataIndex: "status", width: "100px", align: "center", ellipsis: true, scopedSlots: { customRender: "status" } },
{ title: "触发类型", dataIndex: "triggerBuildType", align: "center", width: "100px", ellipsis: true, scopedSlots: { customRender: "triggerBuildType" } },
@@ -151,7 +151,7 @@ export default {
},
{ title: "发布方式", dataIndex: "releaseMethod", width: "100px", ellipsis: true, scopedSlots: { customRender: "releaseMethod" } },
{ title: "构建人", dataIndex: "modifyUser", width: "130px", ellipsis: true, scopedSlots: { customRender: "modifyUser" } },
- { title: "操作", dataIndex: "operation", scopedSlots: { customRender: "operation" }, width: "200px", align: "center" },
+ { title: "操作", dataIndex: "operation", scopedSlots: { customRender: "operation" }, width: "200px", align: "center", fixed: "right" },
],
};
},
diff --git a/web-vue/src/pages/build/list-info.vue b/web-vue/src/pages/build/list-info.vue
index 2336d3b81..9806ab4fe 100644
--- a/web-vue/src/pages/build/list-info.vue
+++ b/web-vue/src/pages/build/list-info.vue
@@ -1168,16 +1168,17 @@ export default {
afterOptListSimple,
buildConfirmVisible: false,
columns: [
- { title: "名称", dataIndex: "name", sorter: true, ellipsis: true, scopedSlots: { customRender: "name" } },
-
+ { title: "名称", dataIndex: "name", sorter: true, width: 200, ellipsis: true, scopedSlots: { customRender: "name" } },
+ { title: "分组", dataIndex: "group", width: 100, ellipsis: true, scopedSlots: { customRender: "tooltip" } },
{
title: "分支/标签",
dataIndex: "branchName",
ellipsis: true,
+ width: 100,
scopedSlots: { customRender: "branchName" },
},
- { title: "产物", dataIndex: "resultDirFile", ellipsis: true, scopedSlots: { customRender: "tooltip" } },
- { title: "方式", dataIndex: "buildMode", align: "center", width: "80px", ellipsis: true, scopedSlots: { customRender: "buildMode" } },
+ { title: "产物", dataIndex: "resultDirFile", width: 100, ellipsis: true, scopedSlots: { customRender: "tooltip" } },
+ { title: "方式", dataIndex: "buildMode", align: "center", width: "80px", sorter: true, ellipsis: true, scopedSlots: { customRender: "buildMode" } },
{ title: "状态", dataIndex: "status", align: "center", width: "100px", ellipsis: true, scopedSlots: { customRender: "status" } },
{
title: "构建 ID",
@@ -1200,28 +1201,24 @@ export default {
dataIndex: "modifyTimeMillis",
sorter: true,
customRender: (text) => {
- if (!text) {
- return "";
- }
return parseTime(text);
},
- width: 170,
+ width: "170px",
},
{
- title: "其他信息",
+ title: "发布方式",
dataIndex: "releaseMethod",
- width: 100,
+ width: "100px",
ellipsis: true,
scopedSlots: { customRender: "releaseMethod" },
},
- // {
- // title: "产物目录",
- // dataIndex: "resultDirFile",
- // ellipsis: true,
- // width: 100,
- // scopedSlots: { customRender: "resultDirFile" },
- // },
- // { title: "构建命令", width: 100, dataIndex: "script", ellipsis: true, scopedSlots: { customRender: "script" } },
+ {
+ title: "定时构建",
+ dataIndex: "autoBuildCron",
+ width: 100,
+ ellipsis: true,
+ scopedSlots: { customRender: "tooltip" },
+ },
{
title: "操作",
dataIndex: "operation",
@@ -1804,9 +1801,10 @@ export default {
// 选择发布集群时 渲染服务名称 数据
selectSwarm() {
this.swarmServiceListOptions = [];
+ this.tempExtraData = { ...this.tempExtraData, dockerSwarmServiceName: undefined };
if (this.tempExtraData.dockerSwarmId) {
// 选中时才处理
- dockerSwarmServicesList({
+ dockerSwarmServicesList("", {
id: this.tempExtraData.dockerSwarmId,
}).then((res) => {
if (res.code === 200) {
diff --git a/web-vue/src/pages/docker/list.vue b/web-vue/src/pages/docker/list.vue
index 7205df67d..06ad75ac4 100644
--- a/web-vue/src/pages/docker/list.vue
+++ b/web-vue/src/pages/docker/list.vue
@@ -46,7 +46,7 @@
-
+
diff --git a/web-vue/src/pages/layout/user-header.vue b/web-vue/src/pages/layout/user-header.vue
index 7db5f2d4c..ca8d98f74 100644
--- a/web-vue/src/pages/layout/user-header.vue
+++ b/web-vue/src/pages/layout/user-header.vue
@@ -31,21 +31,19 @@
-
- 安全管理
-
+ 安全管理
-
- 用户资料
-
+ 用户资料
-
-
- 个性配置
-
+
+ 操作日志
+
+
+
+ 个性配置
@@ -277,6 +275,10 @@
+
+
+
+
diff --git a/web-vue/src/pages/layout/user-log.vue b/web-vue/src/pages/layout/user-log.vue
new file mode 100644
index 000000000..fa0c2d402
--- /dev/null
+++ b/web-vue/src/pages/layout/user-log.vue
@@ -0,0 +1,226 @@
+
+
+
+
+
+ {
+ this.operatelistQuery = CHANGE_PAGE(this.operatelistQuery, { pagination, sorter });
+ this.operaterloadData();
+ }
+ "
+ >
+
+
+
+ {{ item.title }}
+
+
+ {{ item.title }}
+
+ {
+ this.operatelistQuery.createTimeMillis = `${dateString[0]} ~ ${dateString[1]}`;
+ }
+ "
+ />
+
+ 搜索
+
+
+
+
+
+ {{ classFeatureMap[text] }}
+
+
+ {{ methodFeatureMap[text] }}
+
+
+ {{ text }}
+
+
+
+ {{ text || item.userId }}
+
+
+
+ {{ text }}
+
+
+
+
+ {
+ this.loginlistQuery = CHANGE_PAGE(this.loginlistQuery, { pagination, sorter });
+ this.loginloadData();
+ }
+ "
+ >
+
+
+
+
+ {
+ this.loginlistQuery.createTimeMillis = `${dateString[0]} ~ ${dateString[1]}`;
+ }
+ "
+ />
+
+ 搜索
+
+
+
+
+ 成功
+ 失败
+
+
+ {{ text ? "使用" : "未使用" }}
+
+
+
+ {{ text }}
+
+
+
+ {{ operateCode[text] || "未知" }}
+
+
+
+
+
+
+
diff --git a/web-vue/src/pages/login/index.vue b/web-vue/src/pages/login/index.vue
index 144e335f6..c7f9540fc 100644
--- a/web-vue/src/pages/login/index.vue
+++ b/web-vue/src/pages/login/index.vue
@@ -30,8 +30,8 @@
-
-
+
+
@@ -73,7 +73,7 @@ export default {
data() {
return {
loginForm: {
- userName: "",
+ loginName: "",
userPwd: "",
code: "",
},
@@ -83,7 +83,7 @@ export default {
dynamicBg: localStorage.getItem("dynamicBg") === "true",
loginTitle: "登录JPOM",
rules: {
- userName: [{ required: true, message: "请输入用户名" }],
+ loginName: [{ required: true, message: "请输入用户名" }],
userPwd: [{ required: true, message: "请输入密码" }],
code: [{ required: true, message: "请输入验证码" }],
mfaCode: [
@@ -147,7 +147,7 @@ export default {
message: "温馨提示",
description: h("div", null, [h("p", { domProps: { innerHTML: res.msg } }, null)]),
});
- this.loginForm.userName = res.data.user;
+ this.loginForm.loginName = res.data.user;
}
});
},
diff --git a/web-vue/src/pages/system/taskStat.vue b/web-vue/src/pages/system/taskStat.vue
index a03e61ade..3b19c0b72 100644
--- a/web-vue/src/pages/system/taskStat.vue
+++ b/web-vue/src/pages/system/taskStat.vue
@@ -10,6 +10,10 @@
{{ parseTime(text) }}
+
+
+ {{ text }}
+
@@ -58,6 +62,7 @@ export default {
{
title: "cron",
dataIndex: "cron",
+ scopedSlots: { customRender: "cron" },
// sorter: (a, b) => (a && b ? a.localeCompare(b, "zh-CN") : 0),
// sortDirections: ["descend", "ascend"],
},
@@ -100,6 +105,20 @@ export default {
refresh() {
this.$emit("refresh");
},
+ // 前往 cron 详情
+ toCronTaskList(cron) {
+ const newpage = this.$router.resolve({
+ name: "cron-task-list",
+ path: "/tools/cron",
+ query: {
+ ...this.$route.query,
+ sPid: "tools",
+ sId: "cronTools",
+ cron: cron,
+ },
+ });
+ window.open(newpage.href, "_blank");
+ },
},
};
diff --git a/web-vue/src/pages/system/workspace.vue b/web-vue/src/pages/system/workspace.vue
index 015f2d212..5c8e22f0d 100644
--- a/web-vue/src/pages/system/workspace.vue
+++ b/web-vue/src/pages/system/workspace.vue
@@ -56,6 +56,7 @@
+
diff --git a/web-vue/src/pages/test/index.vue b/web-vue/src/pages/test/index.vue
deleted file mode 100644
index 01eec5958..000000000
--- a/web-vue/src/pages/test/index.vue
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
diff --git a/web-vue/src/pages/tools/cron.vue b/web-vue/src/pages/tools/cron.vue
new file mode 100644
index 000000000..61405bfc6
--- /dev/null
+++ b/web-vue/src/pages/tools/cron.vue
@@ -0,0 +1,153 @@
+
+
+
+
+
+
+
+
+ 定时任务表达式
+ 表达式类似于Linux的crontab表达式,表达式使用空格分成5个部分,按顺序依次为:
+
+ - 分 :范围:0~59
+ - 时 :范围:0~23
+ - 日 :范围:1~31,"L" 表示月的最后一天
+ - 月 :范围:1~12,同时支持不区分大小写的别名:"jan","feb", "mar", "apr", "may","jun", "jul", "aug", "sep","oct", "nov", "dec"
+ - 周 :范围:0 (Sunday)~6(Saturday),7也可以表示周日,同时支持不区分大小写的别名:"sun","mon", "tue", "wed", "thu","fri", "sat","L" 表示周六
+
+ 为了兼容Quartz表达式,同时支持6位和7位表达式,其中:
+
+
+ 当为6位时,第一位表示秒 ,范围0~59,但是第一位不做匹配
+ 当为7位时,最后一位表示年 ,范围1970~2099,但是第7位不做解析,也不做匹配
+
+
+ 当定时任务运行到的时间匹配这些表达式后,任务被启动。
+ 注意:
+
+
+
+ 当isMatchSecond为 true 时才会匹配秒部分
+ 默认都是关闭的
+
+ 对于每一个子表达式,同样支持以下形式:
+
+
+ - * :表示匹配这个位置所有的时间
+ - ? :表示匹配这个位置任意的时间(与"*"作用一致)
+ - */2 :表示间隔时间,例如在分上,表示每两分钟,同样*可以使用数字列表代替,逗号分隔
+ - 2-8 :表示连续区间,例如在分上,表示2,3,4,5,6,7,8分
+ - 2,3,5,8 :表示列表
+ - cronA | cronB :表示多个定时表达式
+
+ 注意:在每一个子表达式中优先级:
+
+
+ 间隔(/) > 区间(-) > 列表(,)
+
+
+ 例如 2,3,6/3中,由于“/”优先级高,因此相当于2,3,(6/3),结果与 2,3,6等价
+
+
+
+ 一些例子:
+
+
+ - 5 * * * * :每个点钟的5分执行,00:05,01:05……
+ - * * * * * :每分钟执行
+ - */2 * * * * :每两分钟执行
+ - * 12 * * * :12点的每分钟执行
+ - 59 11 * * 1,2 :每周一和周二的11:59执行
+ - 3-18/5 * * * * :3~18分,每5分钟执行一次,即0:03, 0:08, 0:13, 0:18, 1:03, 1:08……
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 检查
+
+
+
+
+
+
+
+
+ {{ parseTime(item, "{y}-{m}-{d} {h}:{i}:{s} 周{a}") }}
+
+ 结果
+
+
+
+
+
+
diff --git a/web-vue/src/pages/user/operation-log.vue b/web-vue/src/pages/user/operation-log.vue
index 1b2369b1b..ddcdb770a 100644
--- a/web-vue/src/pages/user/operation-log.vue
+++ b/web-vue/src/pages/user/operation-log.vue
@@ -34,6 +34,11 @@
{{ text }}
+
+
+ {{ text || item.userId }}
+
+
{{ text }}
@@ -84,11 +89,12 @@ export default {
detailVisible: false,
detailData: [],
columns: [
- { title: "操作者", dataIndex: "userId" },
+ { title: "操作者", dataIndex: "username", ellipsis: true, scopedSlots: { customRender: "username" } },
{ title: "IP", dataIndex: "ip" /*width: 130*/ },
{ title: "节点", dataIndex: "nodeId", width: 120, ellipsis: true, scopedSlots: { customRender: "nodeId" } },
{ title: "数据名称", dataIndex: "dataName", /*width: 240,*/ ellipsis: true, scopedSlots: { customRender: "tooltip" } },
- { title: "数据 ID", dataIndex: "dataId", /*width: 240,*/ ellipsis: true, scopedSlots: { customRender: "tooltip" } },
+ { title: "工作空间名", dataIndex: "workspaceName", /*width: 240,*/ ellipsis: true, scopedSlots: { customRender: "tooltip" } },
+ // { title: "数据 ID", dataIndex: "dataId", /*width: 240,*/ ellipsis: true, scopedSlots: { customRender: "tooltip" } },
{ title: "操作功能", dataIndex: "classFeature", /*width: 240,*/ ellipsis: true, scopedSlots: { customRender: "classFeature" } },
{ title: "操作方法", dataIndex: "methodFeature", /*width: 240,*/ ellipsis: true, scopedSlots: { customRender: "methodFeature" } },
{ title: "状态码", dataIndex: "optStatus", width: 90, scopedSlots: { customRender: "optStatus" } },
@@ -99,7 +105,7 @@ export default {
customRender: (text, item) => {
return parseTime(text || item.optTime);
},
- width: 160,
+ width: "170px",
},
{ title: "操作", align: "center", dataIndex: "operation", scopedSlots: { customRender: "operation" }, width: 80 },
],
@@ -183,6 +189,7 @@ export default {
} catch (e) {
console.error(e);
}
+ this.detailData.push({ title: "数据Id", description: this.temp.dataId });
this.detailData.push({ title: "浏览器标识", description: this.temp.userAgent });
this.detailData.push({ title: "请求参数", json: true, value: this.temp.reqData });
this.detailData.push({ title: "响应结果", json: true, value: this.temp.resultMsg });
diff --git a/web-vue/src/pages/user/user-login-log.vue b/web-vue/src/pages/user/user-login-log.vue
new file mode 100644
index 000000000..8ca90707c
--- /dev/null
+++ b/web-vue/src/pages/user/user-login-log.vue
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
+
+
+ 搜索
+
+
+
+
+ 成功
+ 失败
+
+
+ {{ text ? "使用" : "未使用" }}
+
+
+
+ {{ text }}
+
+
+
+ {{ operateCode[text] || "未知" }}
+
+
+
+
+
+
diff --git a/web-vue/src/router/index.js b/web-vue/src/router/index.js
index afe601d96..0af19df4e 100644
--- a/web-vue/src/router/index.js
+++ b/web-vue/src/router/index.js
@@ -129,6 +129,11 @@ const children = [
name: "script-env-list",
component: () => import("../pages/script/env"),
},
+ {
+ path: "/tools/cron",
+ name: "cron-tools",
+ component: () => import("../pages/tools/cron"),
+ },
];
const management = [
@@ -162,7 +167,11 @@ const management = [
name: "operation-log",
component: () => import("../pages/user/operation-log"),
},
-
+ {
+ path: "/user/login-log",
+ name: "user-login-log",
+ component: () => import("../pages/user/user-login-log"),
+ },
// 工作空间
{
path: "/system/workspace",
diff --git a/web-vue/src/router/route-menu.js b/web-vue/src/router/route-menu.js
index d0d675361..5bdee86f8 100644
--- a/web-vue/src/router/route-menu.js
+++ b/web-vue/src/router/route-menu.js
@@ -31,6 +31,7 @@ const routeMenuMap = {
userList: "/user/list",
permission_group: "/user/permission-group",
user_log: "/operation/log",
+ user_login_log: "/user/login-log",
monitorConfigEmail: "/system/mail",
cacheManage: "/system/cache",
logManage: "/system/log",
@@ -46,6 +47,7 @@ const routeMenuMap = {
machine_ssh_info: "/system/assets/ssh-list",
machine_docker_info: "/system/assets/docker-list",
configWorkspaceEnv: "/script/env-list",
+ cronTools: "/tools/cron",
};
export default routeMenuMap;
diff --git a/web-vue/src/utils/upload-pieces.js b/web-vue/src/utils/upload-pieces.js
index 7fdfbf694..b27823ab3 100644
--- a/web-vue/src/utils/upload-pieces.js
+++ b/web-vue/src/utils/upload-pieces.js
@@ -108,9 +108,11 @@ export const uploadPieces = ({ file, uploadCallback, success, process, error })
**/
const concurrentUpload = () => {
const startTime = new Date().getTime();
+ // 设置初始化进度(避免第一份分片卡顿)
+ process(0.01, 1, total, new Date().getTime() - startTime);
concurrentExecution(chunkList, uploadFileConcurrent, (curItem) => {
return new Promise((resolve, reject) => {
- const { chunk, end } = getChunkInfo(file, curItem, chunkSize);
+ const { chunk } = getChunkInfo(file, curItem, chunkSize);
const chunkInfo = {
chunk,
currentChunk: curItem,
@@ -125,7 +127,7 @@ export const uploadPieces = ({ file, uploadCallback, success, process, error })
uploaded.push(chunkInfo.currentChunk + 1);
const sd = parseInt((uploaded.length / chunkInfo.chunkCount) * 100);
// console.log(chunk);
- process(sd, end, total, new Date().getTime() - startTime);
+ process(sd, Math.min(uploaded.length * chunkSize, total), total, new Date().getTime() - startTime);
//
/***
* 创建文件上传参数