Merge remote-tracking branch 'origin/feature/20260713/task-module'
This commit is contained in:
@@ -2,13 +2,15 @@ package cn.code.nl.framework.common.pojo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 基础DTO对象
|
||||
* @Author: liyongde
|
||||
* @Date: 2026/7/24 8:49
|
||||
*/
|
||||
@Data
|
||||
public class AcsBaseReqDTO {
|
||||
public class AcsBaseReqDTO implements Serializable {
|
||||
/**
|
||||
* 请求号: traceId
|
||||
*/
|
||||
|
||||
@@ -2,13 +2,15 @@ package cn.code.nl.framework.common.pojo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* acs返回基础对象
|
||||
* @Author: liyongde
|
||||
* @Date: 2026/7/24 10:27
|
||||
*/
|
||||
@Data
|
||||
public class AcsBaseRespDTO {
|
||||
public class AcsBaseRespDTO implements Serializable {
|
||||
/**
|
||||
* 是否整体成功
|
||||
*/
|
||||
@@ -23,4 +25,15 @@ public class AcsBaseRespDTO {
|
||||
* 响应消息
|
||||
*/
|
||||
private String msg;
|
||||
|
||||
/**
|
||||
* 请求号: traceId
|
||||
*/
|
||||
private String traceId;
|
||||
|
||||
/**
|
||||
*
|
||||
* 时间
|
||||
*/
|
||||
private Long timestamp;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,12 @@
|
||||
<artifactId>nl-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.nl.cloud</groupId>
|
||||
<artifactId>nl-module-infra-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring 核心 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
||||
@@ -2,6 +2,7 @@ package cn.code.nl.framework.execute.config;
|
||||
|
||||
import cn.code.nl.framework.execute.biz.api.lms.LmsTaskCommonApi;
|
||||
import cn.code.nl.framework.execute.biz.api.wms.WmsTaskCommonApi;
|
||||
import cn.code.nl.module.infra.api.config.ConfigApi;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
|
||||
@@ -13,6 +14,6 @@ import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
* @Date: 2026/7/15
|
||||
*/
|
||||
@AutoConfiguration
|
||||
@EnableFeignClients(clients = {LmsTaskCommonApi.class, WmsTaskCommonApi.class})
|
||||
@EnableFeignClients(clients = {LmsTaskCommonApi.class, WmsTaskCommonApi.class, ConfigApi.class})
|
||||
public class NlExecuteRpcAutoConfiguration {
|
||||
}
|
||||
|
||||
@@ -1,33 +1,49 @@
|
||||
package cn.code.nl.framework.common.util.http;
|
||||
package cn.code.nl.framework.execute.util.http;
|
||||
|
||||
import cn.code.nl.framework.common.exception.ServerException;
|
||||
import cn.code.nl.framework.common.exception.ServiceException;
|
||||
import cn.code.nl.framework.common.pojo.AcsBaseRespDTO;
|
||||
import cn.code.nl.framework.common.util.http.HttpUtils;
|
||||
import cn.code.nl.framework.common.util.json.JsonUtils;
|
||||
import cn.code.nl.framework.common.util.spring.SpringUtils;
|
||||
import cn.code.nl.module.infra.api.config.ConfigApi;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.net.ConnectException;
|
||||
import java.net.NoRouteToHostException;
|
||||
import java.net.SocketException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.net.*;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* ACS 调用工具
|
||||
*/
|
||||
@Slf4j
|
||||
public class AcsUtil {
|
||||
|
||||
/**
|
||||
* ACS 开关配置
|
||||
*/
|
||||
private static final String ACS_SWITCH_CONFIG_KEY = "acs_switch_config";
|
||||
|
||||
/**
|
||||
* ACS 不启用
|
||||
*/
|
||||
private static final String ACS_DISABLED = "0";
|
||||
|
||||
/**
|
||||
* 发送 POST 请求并解析响应
|
||||
*
|
||||
* @param serverAddress ACS 服务地址
|
||||
* @param api API 路径
|
||||
* @param request 请求参数
|
||||
* @param responseType 响应类型
|
||||
* @param api API 路径
|
||||
* @param request 请求参数
|
||||
* @param responseType 响应类型
|
||||
* @return 响应对象
|
||||
*/
|
||||
public static <T> T post(String serverAddress, String api, Object request, Class<T> responseType) {
|
||||
if (isAcsDisabled()) {
|
||||
return buildDefaultSuccessResponse(responseType);
|
||||
}
|
||||
String url = buildUrl(serverAddress, api);
|
||||
String response;
|
||||
try {
|
||||
@@ -41,6 +57,40 @@ public class AcsUtil {
|
||||
return JsonUtils.parseObject(response, responseType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否关闭 ACS
|
||||
*/
|
||||
private static boolean isAcsDisabled() {
|
||||
String configValue = getAcsSwitchConfigValue();
|
||||
return StrUtil.equals(ACS_DISABLED, configValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 ACS 开关配置
|
||||
*/
|
||||
private static String getAcsSwitchConfigValue() {
|
||||
try {
|
||||
ConfigApi configApi = SpringUtils.getBean("configApi");
|
||||
String checkedData = configApi.getConfigValueByKey(ACS_SWITCH_CONFIG_KEY).getCheckedData();
|
||||
return ObjectUtil.isEmpty(checkedData) ? ACS_DISABLED : checkedData;
|
||||
} catch (Exception ex) {
|
||||
log.error("获取 ACS 开关配置失败", ex);
|
||||
return ACS_DISABLED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建默认成功响应
|
||||
*/
|
||||
private static <T> T buildDefaultSuccessResponse(Class<T> responseType) {
|
||||
AcsBaseRespDTO response = new AcsBaseRespDTO();
|
||||
response.setSuccess(true);
|
||||
response.setCode("200");
|
||||
response.setTraceId(IdUtil.simpleUUID());
|
||||
response.setTimestamp(System.currentTimeMillis());
|
||||
return JsonUtils.convertObject(response, responseType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼接服务地址和 API
|
||||
*/
|
||||
@@ -39,4 +39,8 @@ public interface LogRecordConstants {
|
||||
String TASK_INFO = "任务信息";
|
||||
String TASK_INFO_OPERATE_TYPE = "操作任务状态";
|
||||
String TASK_INFO_OPERATE_SUCCESS = "{{#loginUserNickname}}对任务操作了{{#operateName}}";
|
||||
String TASK_INFO_ACS_OPERATE_SUCCESS = "ACS 操作任务 {{#operateName}}";
|
||||
String TASK_INFO_ACS_EXECUTE_SUCCESS = "ACS {{#operateName}}";
|
||||
String TASK_INFO_CREATE_BY_RPC = "{{#ownerService}} 创建了任务";
|
||||
String TASK_INFO_CALL_BY_RPC = "{{#ownerService}} 回调任务:{{#taskId}}";
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import cn.code.nl.framework.common.pojo.PageResult;
|
||||
import cn.code.nl.framework.common.util.object.BeanUtils;
|
||||
import cn.code.nl.framework.excel.core.util.ExcelUtils;
|
||||
import cn.code.nl.framework.translate.core.TranslateUtils;
|
||||
import cn.code.nl.module.system.api.logger.dto.OperateLogPageReqDTO;
|
||||
import cn.code.nl.module.system.api.logger.dto.OperateLogRespDTO;
|
||||
import cn.code.nl.module.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO;
|
||||
import cn.code.nl.module.system.controller.admin.logger.vo.operatelog.OperateLogRespVO;
|
||||
import cn.code.nl.module.system.dal.dataobject.logger.OperateLogDO;
|
||||
@@ -58,6 +60,15 @@ public class OperateLogController {
|
||||
return success(BeanUtils.toBean(pageResult, OperateLogRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/page2")
|
||||
@Operation(summary = "查看操作日志分页列表2")
|
||||
@PreAuthorize("@ss.hasPermission('system:operate-log:query')")
|
||||
@TransMethodResult
|
||||
public CommonResult<PageResult<OperateLogRespDTO>> getOperateLogPage(OperateLogPageReqDTO pageReqDTO) {
|
||||
PageResult<OperateLogDO> operateLogPage = operateLogService.getOperateLogPage(pageReqDTO);
|
||||
return success(BeanUtils.toBean(operateLogPage, OperateLogRespDTO.class));
|
||||
}
|
||||
|
||||
@Operation(summary = "导出操作日志")
|
||||
@GetMapping("/export-excel")
|
||||
@PreAuthorize("@ss.hasPermission('system:operate-log:export')")
|
||||
|
||||
@@ -39,6 +39,10 @@ public interface TransportTaskApi {
|
||||
@Operation(summary = "根据 taskId 下发搬运任务")
|
||||
CommonResult<Boolean> issueTransportTask(@RequestParam("taskId") Long taskId);
|
||||
|
||||
@PostMapping(PREFIX + "/issue-rollback")
|
||||
@Operation(summary = "根据 taskId 下发搬运任务可回滚")
|
||||
CommonResult<Boolean> issueTransportTaskRollBack(@RequestParam("taskId") Long taskId);
|
||||
|
||||
@GetMapping(PREFIX + "/getTaskById")
|
||||
@Operation(summary = "根据 taskId 查询任务")
|
||||
CommonResult<TaskInfoDTO> getTaskById(@RequestParam("taskId") Long taskId);
|
||||
|
||||
@@ -17,5 +17,13 @@ public interface ErrorCodeConstants {
|
||||
ErrorCode TRANSPORT_TASK_OPERATION_NOT_SUPPORTED = new ErrorCode(5006, "不支持的任务操作类型");
|
||||
ErrorCode TRANSPORT_TASK_ALREADY_FINAL = new ErrorCode(5007, "任务已处于终态,不允许操作");
|
||||
ErrorCode TRANSPORT_TASK_AUTO_ISSUE_NOT_ALLOW_MANUAL = new ErrorCode(5008, "自动任务不允许手动下发");
|
||||
ErrorCode TRANSPORT_TASK_OPERATING = new ErrorCode(5009, "任务标识为:{}的任务正在操作中!");
|
||||
ErrorCode TRANSPORT_TASK_ISSUE_FAILED = new ErrorCode(5010, "任务下发失败,失败原因:{}");
|
||||
ErrorCode TRANSPORT_TASK_ACS_SERVER_ADDRESS_NOT_CONFIGURED = new ErrorCode(5011, "未配置 ACS 服务地址:{}");
|
||||
ErrorCode TRANSPORT_TASK_ACS_OPERATE_CHECK_FAILED = new ErrorCode(5012, "ACS操作校验失败");
|
||||
ErrorCode TRANSPORT_TASK_PRODUCT_AREA_EMPTY = new ErrorCode(5013, "{}生产区域为空,无法获取 ACS 服务地址");
|
||||
ErrorCode TRANSPORT_TASK_ACS_OPERATE_CHECK_RESULT_EMPTY = new ErrorCode(5014, "ACS 操作校验返回为空");
|
||||
ErrorCode TRANSPORT_TASK_ACS_OPERATE_NOT_ALLOW = new ErrorCode(5015, "ACS 不允许执行该操作,原因:{}");
|
||||
ErrorCode TRANSPORT_TASK_OPERATION_FAILED = new ErrorCode(5016, "任务操作失败,失败原因:{}");
|
||||
|
||||
}
|
||||
|
||||
@@ -44,6 +44,12 @@ public class TransportTaskApiImpl implements TransportTaskApi {
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> issueTransportTaskRollBack(Long taskId) {
|
||||
transportTaskService.issueTransportTaskRollBack(taskId);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<TaskInfoDTO> getTaskById(Long taskId) {
|
||||
return success(transportTaskService.getTaskInfoById(taskId));
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package cn.code.nl.module.task.manage;
|
||||
|
||||
import cn.code.nl.framework.common.exception.ServiceException;
|
||||
import cn.code.nl.framework.common.pojo.CommonResult;
|
||||
import cn.code.nl.framework.execute.biz.api.TaskCommonApi;
|
||||
import cn.code.nl.framework.execute.biz.dto.TaskStatusCallApiReqDTO;
|
||||
@@ -22,6 +21,8 @@ import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import static cn.code.nl.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.code.nl.module.task.enums.ErrorCodeConstants.TRANSPORT_TASK_OPERATING;
|
||||
import static cn.code.nl.module.task.framework.common.util.TaskUtil.isAllowedFrom;
|
||||
|
||||
/**
|
||||
@@ -81,7 +82,7 @@ public class TransportTaskBusinessOperationManager {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new ServiceException(5007, "任务标识为:" + task.getTaskId() + "的任务正在操作中!");
|
||||
throw exception(TRANSPORT_TASK_OPERATING, task.getTaskId());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ package cn.code.nl.module.task.manage;
|
||||
|
||||
import cn.code.nl.framework.common.exception.ServiceException;
|
||||
import cn.code.nl.framework.common.pojo.CommonResult;
|
||||
import cn.code.nl.framework.common.util.http.AcsUtil;
|
||||
import cn.code.nl.framework.common.util.json.JsonUtils;
|
||||
import cn.code.nl.framework.execute.util.http.AcsUtil;
|
||||
import cn.code.nl.module.infra.api.config.ConfigApi;
|
||||
import cn.code.nl.module.task.dal.dataobject.transporttask.TransportTaskDO;
|
||||
import cn.code.nl.module.task.dal.mysql.transporttask.TransportTaskMapper;
|
||||
@@ -24,7 +24,11 @@ import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.code.nl.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.code.nl.module.task.enums.AcsApiConstants.ACS_TASK_API;
|
||||
import static cn.code.nl.module.task.enums.ErrorCodeConstants.TRANSPORT_TASK_ACS_SERVER_ADDRESS_NOT_CONFIGURED;
|
||||
import static cn.code.nl.module.task.enums.ErrorCodeConstants.TRANSPORT_TASK_ISSUE_FAILED;
|
||||
import static cn.code.nl.module.task.enums.ErrorCodeConstants.TRANSPORT_TASK_PRODUCT_AREA_EMPTY;
|
||||
|
||||
/**
|
||||
* 搬运任务下发管理器
|
||||
@@ -57,6 +61,29 @@ public class TransportTaskIssueManager {
|
||||
taskMap.forEach(this::issueProductAreaTasks);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下发单个任务到 ACS,失败时直接抛出异常
|
||||
*
|
||||
* @param task 待下发任务
|
||||
*/
|
||||
public void issueTask(TransportTaskDO task) {
|
||||
if (StrUtil.isBlank(task.getProductArea())) {
|
||||
throw exception(TRANSPORT_TASK_PRODUCT_AREA_EMPTY, "任务下发失败,失败原因:");
|
||||
}
|
||||
List<AcsTaskDTO> acsTasks = List.of(AcsTaskUtil.buildAcsTaskDTO(task));
|
||||
String requestJson = JsonUtils.toJsonString(acsTasks);
|
||||
try {
|
||||
String serverAddress = getAcsServerAddress(task.getProductArea());
|
||||
AcsIssueResultRespDTO result = AcsUtil.post(serverAddress, ACS_TASK_API, acsTasks, AcsIssueResultRespDTO.class);
|
||||
handleSingleIssueResult(task, result);
|
||||
} catch (ServiceException ex) {
|
||||
throw ex;
|
||||
} catch (Exception ex) {
|
||||
log.error("下发单个任务失败,productArea={},tasks={}", task.getProductArea(), requestJson, ex);
|
||||
throw exception(TRANSPORT_TASK_ISSUE_FAILED, ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下发单个生产区域的任务
|
||||
*
|
||||
@@ -87,7 +114,7 @@ public class TransportTaskIssueManager {
|
||||
CommonResult<String> result = configApi.getConfigValueByKey(configKey);
|
||||
String serverAddress = result.getCheckedData();
|
||||
if (StrUtil.isBlank(serverAddress)) {
|
||||
throw new ServiceException(500, "未配置 ACS 服务地址:" + configKey);
|
||||
throw exception(TRANSPORT_TASK_ACS_SERVER_ADDRESS_NOT_CONFIGURED, configKey);
|
||||
}
|
||||
return serverAddress;
|
||||
}
|
||||
@@ -125,6 +152,27 @@ public class TransportTaskIssueManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理单个任务的 ACS 下发响应
|
||||
*
|
||||
* @param task 本次下发任务
|
||||
* @param result ACS 响应
|
||||
*/
|
||||
private void handleSingleIssueResult(TransportTaskDO task, AcsIssueResultRespDTO result) {
|
||||
if (result == null) {
|
||||
throw exception(TRANSPORT_TASK_ISSUE_FAILED, "ACS 返回为空");
|
||||
}
|
||||
String resultJson = JsonUtils.toJsonString(result);
|
||||
if (Boolean.TRUE.equals(result.getSuccess())) {
|
||||
transportTaskMapper.updateIssueResult(task.getTaskId(), TransportTaskStatusEnum.ISSUED.getCode(), resultJson, null);
|
||||
return;
|
||||
}
|
||||
String errorMessage = CollUtil.isNotEmpty(result.getFailedTasks())
|
||||
? result.getFailedTasks().get(0).getErrorMessage()
|
||||
: result.getMsg();
|
||||
throw exception(TRANSPORT_TASK_ISSUE_FAILED, StrUtil.blankToDefault(errorMessage, "ACS 下发失败"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新任务为下发失败
|
||||
*
|
||||
|
||||
@@ -2,8 +2,8 @@ package cn.code.nl.module.task.manage;
|
||||
|
||||
import cn.code.nl.framework.common.exception.ServiceException;
|
||||
import cn.code.nl.framework.common.pojo.CommonResult;
|
||||
import cn.code.nl.framework.common.util.http.AcsUtil;
|
||||
import cn.code.nl.framework.common.util.json.JsonUtils;
|
||||
import cn.code.nl.framework.execute.util.http.AcsUtil;
|
||||
import cn.code.nl.module.infra.api.config.ConfigApi;
|
||||
import cn.code.nl.module.task.dal.dataobject.transporttask.TransportTaskDO;
|
||||
import cn.code.nl.module.task.enums.TaskOperationTypeEnum;
|
||||
@@ -14,7 +14,13 @@ import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import static cn.code.nl.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.code.nl.module.task.enums.AcsApiConstants.ACS_OPERATE_CHECK_API;
|
||||
import static cn.code.nl.module.task.enums.ErrorCodeConstants.TRANSPORT_TASK_ACS_OPERATE_CHECK_FAILED;
|
||||
import static cn.code.nl.module.task.enums.ErrorCodeConstants.TRANSPORT_TASK_ACS_OPERATE_CHECK_RESULT_EMPTY;
|
||||
import static cn.code.nl.module.task.enums.ErrorCodeConstants.TRANSPORT_TASK_ACS_OPERATE_NOT_ALLOW;
|
||||
import static cn.code.nl.module.task.enums.ErrorCodeConstants.TRANSPORT_TASK_ACS_SERVER_ADDRESS_NOT_CONFIGURED;
|
||||
import static cn.code.nl.module.task.enums.ErrorCodeConstants.TRANSPORT_TASK_PRODUCT_AREA_EMPTY;
|
||||
|
||||
/**
|
||||
* PC 端任务操作 ACS 校验管理器
|
||||
@@ -50,7 +56,7 @@ public class TransportTaskOperateCheckManager {
|
||||
throw ex;
|
||||
} catch (Exception ex) {
|
||||
log.error("ACS 操作校验请求失败,reqDTO={}", JsonUtils.toJsonString(reqDTO), ex);
|
||||
throw new ServiceException(500, "ACS操作校验失败");
|
||||
throw exception(TRANSPORT_TASK_ACS_OPERATE_CHECK_FAILED);
|
||||
}
|
||||
handleCheckResult(reqDTO, result);
|
||||
}
|
||||
@@ -71,13 +77,13 @@ public class TransportTaskOperateCheckManager {
|
||||
*/
|
||||
private String getAcsServerAddress(String productArea) {
|
||||
if (StrUtil.isBlank(productArea)) {
|
||||
throw new ServiceException(500, "生产区域为空,无法获取 ACS 服务地址");
|
||||
throw exception(TRANSPORT_TASK_PRODUCT_AREA_EMPTY, "");
|
||||
}
|
||||
String configKey = productArea + ACS_SERVER_ADDRESS_CONFIG_SUFFIX;
|
||||
CommonResult<String> result = configApi.getConfigValueByKey(configKey);
|
||||
String serverAddress = result.getCheckedData();
|
||||
if (StrUtil.isBlank(serverAddress)) {
|
||||
throw new ServiceException(500, "未配置 ACS 服务地址:" + configKey);
|
||||
throw exception(TRANSPORT_TASK_ACS_SERVER_ADDRESS_NOT_CONFIGURED, configKey);
|
||||
}
|
||||
return serverAddress;
|
||||
}
|
||||
@@ -99,7 +105,7 @@ public class TransportTaskOperateCheckManager {
|
||||
*/
|
||||
private void handleCheckResult(AcsOperateCheckReqDTO reqDTO, AcsOperateCheckRespDTO result) {
|
||||
if (result == null) {
|
||||
throw new ServiceException(500, "ACS 操作校验返回为空");
|
||||
throw exception(TRANSPORT_TASK_ACS_OPERATE_CHECK_RESULT_EMPTY);
|
||||
}
|
||||
Boolean enableOperate = getEnableOperate(result);
|
||||
if (Boolean.TRUE.equals(enableOperate)) {
|
||||
@@ -108,7 +114,7 @@ public class TransportTaskOperateCheckManager {
|
||||
String message = getMessage(result);
|
||||
log.warn("ACS 拒绝 PC 端任务操作,reqDTO={},result={}",
|
||||
JsonUtils.toJsonString(reqDTO), JsonUtils.toJsonString(result));
|
||||
throw new ServiceException(500, message);
|
||||
throw exception(TRANSPORT_TASK_ACS_OPERATE_NOT_ALLOW, message);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -28,6 +28,8 @@ import java.util.function.BiConsumer;
|
||||
|
||||
import static cn.code.nl.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.code.nl.module.task.enums.ErrorCodeConstants.TRANSPORT_TASK_AUTO_ISSUE_NOT_ALLOW_MANUAL;
|
||||
import static cn.code.nl.module.task.enums.ErrorCodeConstants.TRANSPORT_TASK_OPERATING;
|
||||
import static cn.code.nl.module.task.enums.ErrorCodeConstants.TRANSPORT_TASK_OPERATION_FAILED;
|
||||
import static cn.code.nl.module.task.enums.ErrorCodeConstants.TRANSPORT_TASK_STATUS_NOT_ALLOW;
|
||||
import static cn.code.nl.module.task.framework.common.util.TaskUtil.isAllowedFrom;
|
||||
|
||||
@@ -86,14 +88,14 @@ public class TransportTaskOperationManager {
|
||||
throw serviceException;
|
||||
}
|
||||
log.error("[messageResend][执行异常][lockKey={}]", task.getTaskId(), ex);
|
||||
throw new ServiceException(500, ex.getMessage());
|
||||
throw exception(TRANSPORT_TASK_OPERATION_FAILED, ex.getMessage());
|
||||
} finally {
|
||||
if (lock.isHeldByCurrentThread()) {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new ServiceException(5007, "任务标识为:" + task.getTaskId() + "的任务正在操作中!");
|
||||
throw exception(TRANSPORT_TASK_OPERATING, task.getTaskId());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,12 +5,16 @@ import cn.code.nl.module.task.dal.mysql.transporttask.TransportTaskMapper;
|
||||
import cn.code.nl.module.task.dto.TaskCallbackResultReqDTO;
|
||||
import cn.code.nl.module.task.enums.CallbackStatusEnum;
|
||||
import cn.code.nl.module.task.enums.TransportTaskStatusEnum;
|
||||
import com.mzt.logapi.context.LogRecordContext;
|
||||
import com.mzt.logapi.starter.annotation.LogRecord;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import static cn.code.nl.module.system.enums.LogRecordConstants.*;
|
||||
|
||||
/**
|
||||
* 业务回调结果处理服务实现
|
||||
*
|
||||
@@ -25,6 +29,10 @@ public class TransportTaskCallbackServiceImpl implements TransportTaskCallbackSe
|
||||
private TransportTaskMapper transportTaskMapper;
|
||||
|
||||
@Override
|
||||
@LogRecord(type = TASK_INFO,
|
||||
subType = TASK_INFO_OPERATE_TYPE,
|
||||
bizNo = "{{#reqDTO.taskId}}",
|
||||
success = TASK_INFO_CALL_BY_RPC)
|
||||
public void receiveCallbackResult(TaskCallbackResultReqDTO reqDTO) {
|
||||
// 1. 查询任务
|
||||
TransportTaskDO task = transportTaskMapper.selectById(reqDTO.getTaskId());
|
||||
@@ -62,6 +70,10 @@ public class TransportTaskCallbackServiceImpl implements TransportTaskCallbackSe
|
||||
}
|
||||
|
||||
transportTaskMapper.updateById(task);
|
||||
|
||||
LogRecordContext.putVariable("ownerService", task.getOwnerService());
|
||||
LogRecordContext.putVariable("taskId", task.getTaskId());
|
||||
|
||||
log.info("业务回调结果已处理, taskId={}, result={}, newStatus={}",
|
||||
reqDTO.getTaskId(), reqDTO.getResult(), task.getTaskStatus());
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package cn.code.nl.module.task.service.transporttask;
|
||||
|
||||
import cn.code.nl.framework.common.exception.ServiceException;
|
||||
import cn.code.nl.framework.execute.biz.vo.AcsApplyActionRespVO;
|
||||
import cn.code.nl.module.task.dal.dataobject.transporttask.TransportTaskDO;
|
||||
import cn.code.nl.module.task.dal.mysql.transporttask.TransportTaskMapper;
|
||||
@@ -11,14 +10,16 @@ import cn.code.nl.module.task.enums.TransportTaskStatusEnum;
|
||||
import cn.code.nl.module.task.manage.TransportTaskBusinessOperationManager;
|
||||
import cn.code.nl.module.task.manage.TransportTaskOperationManager;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.mzt.logapi.context.LogRecordContext;
|
||||
import com.mzt.logapi.starter.annotation.LogRecord;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import static cn.code.nl.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.code.nl.module.system.enums.LogRecordConstants.*;
|
||||
import static cn.code.nl.module.task.enums.ErrorCodeConstants.TRANSPORT_TASK_NOT_EXISTS_ID;
|
||||
|
||||
/**
|
||||
@@ -46,6 +47,10 @@ public class TransportTaskFeedbackServiceImpl implements TransportTaskFeedbackSe
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@LogRecord(type = TASK_INFO,
|
||||
subType = TASK_INFO_OPERATE_TYPE,
|
||||
bizNo = "{{#reqDTO.taskId}}",
|
||||
success = TASK_INFO_ACS_OPERATE_SUCCESS)
|
||||
public void receiveAcsFeedback(AcsFeedbackReqDTO reqDTO) {
|
||||
TransportTaskDO task = getTaskForFeedback(reqDTO);
|
||||
saveResultParam(task, reqDTO);
|
||||
@@ -58,10 +63,15 @@ public class TransportTaskFeedbackServiceImpl implements TransportTaskFeedbackSe
|
||||
return;
|
||||
}
|
||||
transportTaskOperationManager.dispatchOperation(task, type, reqDTO);
|
||||
LogRecordContext.putVariable("operateName", type.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@LogRecord(type = TASK_INFO,
|
||||
subType = TASK_INFO_OPERATE_TYPE,
|
||||
bizNo = "{{#reqDTO.taskId}}",
|
||||
success = TASK_INFO_ACS_EXECUTE_SUCCESS)
|
||||
public AcsApplyActionRespVO receiveAcsBusinessFeedback(AcsFeedbackReqDTO reqDTO) {
|
||||
TransportTaskDO task = getTaskForFeedback(reqDTO);
|
||||
if (isFinalTask(task, reqDTO)) {
|
||||
@@ -77,6 +87,7 @@ public class TransportTaskFeedbackServiceImpl implements TransportTaskFeedbackSe
|
||||
reqDTO.getTaskId(), reqDTO.getStatus());
|
||||
return buildResp(task);
|
||||
}
|
||||
LogRecordContext.putVariable("operateName", type.getName());
|
||||
return transportTaskBusinessOperationManager.dispatchOperation(task, type, reqDTO);
|
||||
}
|
||||
|
||||
|
||||
@@ -82,6 +82,12 @@ public interface TransportTaskService {
|
||||
* @param taskId 任务ID
|
||||
*/
|
||||
void issueTransportTask(Long taskId);
|
||||
/**
|
||||
* 根据任务ID下发搬运任务到 ACS 报错回滚
|
||||
*
|
||||
* @param taskId 任务ID
|
||||
*/
|
||||
void issueTransportTaskRollBack(Long taskId);
|
||||
|
||||
/**
|
||||
* 根据 taskId 查询任务全量信息(RPC 用,自动过滤逻辑删除,查不到返回 null)
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package cn.code.nl.module.task.service.transporttask;
|
||||
|
||||
import cn.code.nl.framework.common.pojo.CommonResult;
|
||||
import cn.code.nl.framework.common.pojo.PageResult;
|
||||
import cn.code.nl.framework.common.util.object.BeanUtils;
|
||||
import cn.code.nl.framework.security.core.util.SecurityFrameworkUtils;
|
||||
import cn.code.nl.module.base.api.classstandard.ClassStandardApi;
|
||||
import cn.code.nl.module.base.api.codegen.CodeGenApi;
|
||||
import cn.code.nl.module.base.api.codegen.dto.CodeGenerateReqDTO;
|
||||
import cn.code.nl.module.task.controller.admin.transporttask.vo.TransportTaskOperateReqVO;
|
||||
import cn.code.nl.module.task.controller.admin.transporttask.vo.TransportTaskPageReqVO;
|
||||
import cn.code.nl.module.task.controller.admin.transporttask.vo.TransportTaskSaveReqVO;
|
||||
@@ -34,9 +37,7 @@ import java.util.List;
|
||||
|
||||
import static cn.code.nl.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.code.nl.module.system.enums.LogRecordConstants.*;
|
||||
import static cn.code.nl.module.task.enums.ErrorCodeConstants.TRANSPORT_TASK_ALREADY_FINAL;
|
||||
import static cn.code.nl.module.task.enums.ErrorCodeConstants.TRANSPORT_TASK_NOT_EXISTS;
|
||||
import static cn.code.nl.module.task.enums.ErrorCodeConstants.TRANSPORT_TASK_OPERATION_NOT_SUPPORTED;
|
||||
import static cn.code.nl.module.task.enums.ErrorCodeConstants.*;
|
||||
|
||||
/**
|
||||
* 搬运任务 Service 实现类
|
||||
@@ -63,6 +64,9 @@ public class TransportTaskServiceImpl implements TransportTaskService {
|
||||
@Resource
|
||||
private ClassStandardApi classStandardApi;
|
||||
|
||||
@Resource
|
||||
private CodeGenApi codeGenApi;
|
||||
|
||||
@Override
|
||||
public Long createTransportTask(TransportTaskSaveReqVO createReqVO) {
|
||||
TransportTaskDO transportTask = BeanUtils.toBean(createReqVO, TransportTaskDO.class);
|
||||
@@ -71,8 +75,16 @@ public class TransportTaskServiceImpl implements TransportTaskService {
|
||||
}
|
||||
|
||||
@Override
|
||||
@LogRecord(type = TASK_INFO,
|
||||
subType = TASK_INFO_OPERATE_TYPE,
|
||||
bizNo = "{{_ret}}",
|
||||
success = TASK_INFO_CREATE_BY_RPC)
|
||||
public Long createTransportTaskByRpc(TransportTaskCreateReqDTO reqDTO) {
|
||||
TransportTaskDO task = BeanUtils.toBean(reqDTO, TransportTaskDO.class);
|
||||
CodeGenerateReqDTO codeGenerateReqDTO = new CodeGenerateReqDTO();
|
||||
codeGenerateReqDTO.setRuleCode("TASK_CODE");
|
||||
CommonResult<String> generate = codeGenApi.generate(codeGenerateReqDTO);
|
||||
task.setTaskCode(generate.getCheckedData());
|
||||
task.setTaskStatus(reqDTO.getIsCreateFinish()
|
||||
? TransportTaskStatusEnum.READY.getCode()
|
||||
: TransportTaskStatusEnum.CREATED.getCode());
|
||||
@@ -81,6 +93,7 @@ public class TransportTaskServiceImpl implements TransportTaskService {
|
||||
task.setCreateMode("RPC");
|
||||
|
||||
transportTaskMapper.insert(task);
|
||||
LogRecordContext.putVariable("ownerService", task.getOwnerService());
|
||||
return task.getTaskId();
|
||||
}
|
||||
|
||||
@@ -184,6 +197,15 @@ public class TransportTaskServiceImpl implements TransportTaskService {
|
||||
transportTaskOperationManager.dispatchOperation(task, TaskOperationTypeEnum.ISSUE, reqDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void issueTransportTaskRollBack(Long taskId) {
|
||||
TransportTaskDO task = transportTaskMapper.selectById(taskId);
|
||||
if (task == null) {
|
||||
throw exception(TRANSPORT_TASK_NOT_EXISTS);
|
||||
}
|
||||
transportTaskIssueManager.issueTask(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskInfoDTO getTaskInfoById(Long taskId) {
|
||||
TransportTaskDO task = transportTaskMapper.selectById(taskId);
|
||||
|
||||
@@ -33,6 +33,14 @@ export function getOperateLogPage(params: PageParam) {
|
||||
);
|
||||
}
|
||||
|
||||
/** 查询操作日志列表2 */
|
||||
export function getOperateLogPage2(params: PageParam) {
|
||||
return requestClient.get<PageResult<SystemOperateLogApi.OperateLog>>(
|
||||
'/system/operate-log/page2',
|
||||
{ params },
|
||||
);
|
||||
}
|
||||
|
||||
/** 导出操作日志 */
|
||||
export function exportOperateLog(params: any) {
|
||||
return requestClient.download('/system/operate-log/export-excel', { params });
|
||||
|
||||
@@ -5,6 +5,7 @@ import { requestClient } from '#/api/request';
|
||||
export namespace TaskTransportTaskApi {
|
||||
/** 搬运任务信息 */
|
||||
export interface TransportTask {
|
||||
id?: number | string;
|
||||
taskId?: string;
|
||||
taskCode?: string; // 任务编码
|
||||
taskName: string; // 任务名称
|
||||
@@ -52,7 +53,7 @@ export function getTransportTaskPage(params: PageParam) {
|
||||
}
|
||||
|
||||
/** 查询搬运任务详情 */
|
||||
export function getTransportTask(id: number) {
|
||||
export function getTransportTask(id: number | string) {
|
||||
return requestClient.get<TaskTransportTaskApi.TransportTask>(
|
||||
`/task/transport-task/get?id=${id}`,
|
||||
);
|
||||
@@ -69,12 +70,12 @@ export function updateTransportTask(data: TaskTransportTaskApi.TransportTask) {
|
||||
}
|
||||
|
||||
/** 删除搬运任务 */
|
||||
export function deleteTransportTask(id: number) {
|
||||
export function deleteTransportTask(id: number | string) {
|
||||
return requestClient.delete(`/task/transport-task/delete?id=${id}`);
|
||||
}
|
||||
|
||||
/** 批量删除搬运任务 */
|
||||
export function deleteTransportTaskList(ids: number[]) {
|
||||
export function deleteTransportTaskList(ids: Array<number | string>) {
|
||||
return requestClient.delete(
|
||||
`/task/transport-task/delete-list?ids=${ids.join(',')}`,
|
||||
);
|
||||
|
||||
@@ -1,15 +1,28 @@
|
||||
<script lang="ts" setup>
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import type { SystemOperateLogApi } from '#/api/system/operate-log';
|
||||
import type { TaskTransportTaskApi } from '#/api/task/transporttask';
|
||||
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
|
||||
import { confirm, Page, useVbenModal } from '@vben/common-ui';
|
||||
import { downloadFileFromBlobPart, isEmpty } from '@vben/utils';
|
||||
import { downloadFileFromBlobPart, formatDateTime, isEmpty } from '@vben/utils';
|
||||
|
||||
import { message } from 'antdv-next';
|
||||
import {
|
||||
Button,
|
||||
Descriptions,
|
||||
DescriptionsItem,
|
||||
Drawer,
|
||||
Empty,
|
||||
message,
|
||||
Modal,
|
||||
Spin,
|
||||
Timeline,
|
||||
TimelineItem,
|
||||
} from 'antdv-next';
|
||||
|
||||
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import { getOperateLogPage2 } from '#/api/system/operate-log';
|
||||
import {
|
||||
deleteTransportTask,
|
||||
deleteTransportTaskList,
|
||||
@@ -22,13 +35,15 @@ import { $t } from '#/locales';
|
||||
import { loadAllLookupData, useGridColumns, useGridFormSchema } from './data';
|
||||
import Form from './modules/form.vue';
|
||||
|
||||
const OPERATE_LOG_PAGE_SIZE = 20;
|
||||
|
||||
const ready = ref(false);
|
||||
onMounted(async () => {
|
||||
await loadAllLookupData();
|
||||
ready.value = true;
|
||||
});
|
||||
|
||||
const [FormModal, formModalApi] = useVbenModal({
|
||||
const [FormModal] = useVbenModal({
|
||||
connectedComponent: Form,
|
||||
destroyOnClose: true,
|
||||
});
|
||||
@@ -38,11 +53,6 @@ function handleRefresh() {
|
||||
gridApi.query();
|
||||
}
|
||||
|
||||
/** 创建搬运任务 */
|
||||
function handleCreate() {
|
||||
formModalApi.setData(null).open();
|
||||
}
|
||||
|
||||
/** PC 端操作搬运任务(完成/取消/强制完成) */
|
||||
async function handleOperate(
|
||||
row: TaskTransportTaskApi.TransportTask,
|
||||
@@ -95,7 +105,7 @@ async function handleDeleteBatch() {
|
||||
}
|
||||
}
|
||||
|
||||
const checkedIds = ref<number[]>([]);
|
||||
const checkedIds = ref<Array<number | string>>([]);
|
||||
function handleRowCheckboxChange({
|
||||
records,
|
||||
}: {
|
||||
@@ -110,6 +120,66 @@ async function handleExport() {
|
||||
downloadFileFromBlobPart({ fileName: '搬运任务.xls', source: data });
|
||||
}
|
||||
|
||||
const operateLogDrawerOpen = ref(false);
|
||||
const operateLogLoading = ref(false);
|
||||
const operateLogPageNo = ref(1);
|
||||
const operateLogTotal = ref(0);
|
||||
const currentOperateLogTask = ref<TaskTransportTaskApi.TransportTask>();
|
||||
const operateLogList = ref<SystemOperateLogApi.OperateLog[]>([]);
|
||||
const selectedOperateLog = ref<SystemOperateLogApi.OperateLog>();
|
||||
|
||||
const operateLogDrawerTitle = computed(() => {
|
||||
const taskCode = currentOperateLogTask.value?.taskCode;
|
||||
return taskCode ? `操作记录 - ${taskCode}` : '操作记录';
|
||||
});
|
||||
const operateLogHasMore = computed(
|
||||
() => operateLogList.value.length < operateLogTotal.value,
|
||||
);
|
||||
|
||||
async function loadOperateLogs(reset = false) {
|
||||
if (operateLogLoading.value) {
|
||||
return;
|
||||
}
|
||||
const taskId = currentOperateLogTask.value?.taskId;
|
||||
if (!taskId) {
|
||||
return;
|
||||
}
|
||||
if (reset) {
|
||||
operateLogPageNo.value = 1;
|
||||
operateLogTotal.value = 0;
|
||||
operateLogList.value = [];
|
||||
}
|
||||
operateLogLoading.value = true;
|
||||
try {
|
||||
const data = await getOperateLogPage2({
|
||||
pageNo: operateLogPageNo.value,
|
||||
pageSize: OPERATE_LOG_PAGE_SIZE,
|
||||
type: '任务信息',
|
||||
bizId: taskId,
|
||||
});
|
||||
operateLogList.value = [...operateLogList.value, ...(data.list || [])];
|
||||
operateLogTotal.value = data.total || 0;
|
||||
operateLogPageNo.value += 1;
|
||||
} finally {
|
||||
operateLogLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function handleOperateLog(row: TaskTransportTaskApi.TransportTask) {
|
||||
currentOperateLogTask.value = row;
|
||||
selectedOperateLog.value = undefined;
|
||||
operateLogDrawerOpen.value = true;
|
||||
loadOperateLogs(true);
|
||||
}
|
||||
|
||||
function handleOperateLogDrawerClose() {
|
||||
selectedOperateLog.value = undefined;
|
||||
currentOperateLogTask.value = undefined;
|
||||
}
|
||||
|
||||
function handleOperateLogDetail(log: SystemOperateLogApi.OperateLog) {
|
||||
selectedOperateLog.value = log;
|
||||
}
|
||||
|
||||
const [Grid, gridApi] = useVbenVxeGrid({
|
||||
formOptions: {
|
||||
@@ -188,7 +258,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||
type: 'link',
|
||||
icon: ACTION_ICON.CIRCLE_CHECK,
|
||||
auth: ['task:transport-task:finish'],
|
||||
disabled: ['79', '85', '89', '99'].includes(row.taskStatus),
|
||||
disabled: ['79', '85', '89', '99'].includes(row.taskStatus || ''),
|
||||
onClick: handleOperate.bind(null, row, 'FINISHED', '完成任务'),
|
||||
},
|
||||
{
|
||||
@@ -196,7 +266,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||
type: 'link',
|
||||
icon: ACTION_ICON.CIRCLE_X,
|
||||
auth: ['task:transport-task:cancel'],
|
||||
disabled: ['75', '79', '89', '99'].includes(row.taskStatus),
|
||||
disabled: ['75', '79', '89', '99'].includes(row.taskStatus || ''),
|
||||
onClick: handleOperate.bind(null, row, 'CANCELLED', '取消任务'),
|
||||
},
|
||||
{
|
||||
@@ -204,9 +274,16 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||
type: 'link',
|
||||
icon: ACTION_ICON.CANCEL,
|
||||
auth: ['task:transport-task:cancel'],
|
||||
disabled: ['79', '89', '99'].includes(row.taskStatus),
|
||||
disabled: ['79', '89', '99'].includes(row.taskStatus || ''),
|
||||
onClick: handleOperate.bind(null, row, 'FORCE-FINISH', '强制完成任务'),
|
||||
},
|
||||
{
|
||||
label: '操作记录',
|
||||
type: 'link',
|
||||
icon: ACTION_ICON.VIEW,
|
||||
auth: ['system:operate-log:query'],
|
||||
onClick: handleOperateLog.bind(null, row),
|
||||
},
|
||||
{
|
||||
label: $t('common.delete'),
|
||||
type: 'link',
|
||||
@@ -222,5 +299,141 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||
/>
|
||||
</template>
|
||||
</Grid>
|
||||
<Drawer
|
||||
v-model:open="operateLogDrawerOpen"
|
||||
:title="operateLogDrawerTitle"
|
||||
width="560"
|
||||
placement="right"
|
||||
destroy-on-close
|
||||
@close="handleOperateLogDrawerClose"
|
||||
>
|
||||
<Spin :spinning="operateLogLoading && isEmpty(operateLogList)">
|
||||
<Empty v-if="!operateLogLoading && isEmpty(operateLogList)" description="暂无操作记录" />
|
||||
<Timeline v-else class="operate-log-timeline">
|
||||
<TimelineItem v-for="log in operateLogList" :key="log.id">
|
||||
<div class="operate-log-timeline-row" @click="handleOperateLogDetail(log)">
|
||||
<span class="operate-log-time">
|
||||
{{ formatDateTime(log.createTime) }}
|
||||
</span>
|
||||
<span class="operate-log-action">{{ log.action || '-' }}</span>
|
||||
</div>
|
||||
</TimelineItem>
|
||||
</Timeline>
|
||||
</Spin>
|
||||
<div v-if="!isEmpty(operateLogList)" class="operate-log-load-more">
|
||||
<Button
|
||||
v-if="operateLogHasMore"
|
||||
:loading="operateLogLoading"
|
||||
block
|
||||
@click="loadOperateLogs()"
|
||||
>
|
||||
加载更多
|
||||
</Button>
|
||||
<span v-else class="operate-log-finished">已加载全部记录</span>
|
||||
</div>
|
||||
</Drawer>
|
||||
<Modal
|
||||
:open="!!selectedOperateLog"
|
||||
title="操作日志详情"
|
||||
width="760px"
|
||||
:footer="null"
|
||||
@cancel="selectedOperateLog = undefined"
|
||||
>
|
||||
<Descriptions
|
||||
v-if="selectedOperateLog"
|
||||
bordered
|
||||
size="small"
|
||||
:column="1"
|
||||
class="operate-log-descriptions"
|
||||
>
|
||||
<DescriptionsItem label="链路追踪编号">
|
||||
{{ selectedOperateLog.traceId || '-' }}
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="用户名称">
|
||||
{{ selectedOperateLog.userName || '-' }}
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="操作模块类型">
|
||||
{{ selectedOperateLog.type || '-' }}
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="操作模块业务编号">
|
||||
{{ selectedOperateLog.bizId || '-' }}
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="操作内容">
|
||||
{{ selectedOperateLog.action || '-' }}
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="拓展字段">
|
||||
<pre>{{ selectedOperateLog.extra || '-' }}</pre>
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="请求方法名">
|
||||
{{ selectedOperateLog.requestMethod || '-' }}
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="请求地址">
|
||||
{{ selectedOperateLog.requestUrl || '-' }}
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="用户 IP">
|
||||
{{ selectedOperateLog.userIp || '-' }}
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="浏览器 UserAgent">
|
||||
{{ selectedOperateLog.userAgent || '-' }}
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="创建时间">
|
||||
{{ formatDateTime(selectedOperateLog.createTime) }}
|
||||
</DescriptionsItem>
|
||||
</Descriptions>
|
||||
</Modal>
|
||||
</Page>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.operate-log-timeline {
|
||||
padding: 8px 4px 0;
|
||||
}
|
||||
|
||||
.operate-log-timeline-row {
|
||||
display: grid;
|
||||
grid-template-columns: 156px minmax(0, 1fr);
|
||||
gap: 12px;
|
||||
padding: 8px 10px;
|
||||
margin: -8px 0 8px;
|
||||
cursor: pointer;
|
||||
border-radius: 6px;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.operate-log-timeline-row:hover {
|
||||
background-color: hsl(var(--accent));
|
||||
}
|
||||
|
||||
.operate-log-time {
|
||||
font-size: 13px;
|
||||
line-height: 22px;
|
||||
color: hsl(var(--muted-foreground));
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.operate-log-action {
|
||||
min-width: 0;
|
||||
line-height: 22px;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.operate-log-load-more {
|
||||
padding: 8px 4px 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.operate-log-finished {
|
||||
font-size: 13px;
|
||||
color: hsl(var(--muted-foreground));
|
||||
}
|
||||
|
||||
.operate-log-descriptions :deep(pre) {
|
||||
max-height: 180px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
overflow: auto;
|
||||
font-family: inherit;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user