✨ 站内消息.
This commit is contained in:
@@ -12,6 +12,8 @@
|
||||
`2024-05-15` `release`
|
||||
|
||||
* 🌈 新增 站内信模块
|
||||
* 🔨 优化 执行命令日志跳转逻辑
|
||||
* 🔨 修改 `exitStatus` 改为 `exitCode`
|
||||
|
||||
[如何升级](/update/v1.0.8.md)
|
||||
|
||||
|
||||
@@ -55,6 +55,10 @@ public interface FieldConst {
|
||||
|
||||
String COUNT = "count";
|
||||
|
||||
String DATE = "date";
|
||||
|
||||
String TIME = "time";
|
||||
|
||||
String LOCATION = "location";
|
||||
|
||||
String USER_AGENT = "userAgent";
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.orion.ops.module.asset.define.message;
|
||||
|
||||
import com.orion.ops.module.infra.define.SystemMessageDefine;
|
||||
import com.orion.ops.module.infra.enums.MessageClassifyEnum;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 命令执行 系统消息定义
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2024/5/14 17:23
|
||||
*/
|
||||
@Getter
|
||||
public enum ExecMessageDefine implements SystemMessageDefine {
|
||||
|
||||
/**
|
||||
* 命令执行部分失败
|
||||
*/
|
||||
EXEC_FAILED(MessageClassifyEnum.NOTICE,
|
||||
"命令执行失败",
|
||||
"您在 <sb>${time}</sb> 执行的命令部分失败, 或者返回了非零的 exitCode。点击查看详情 <sb>#${id}</sb> >>>"),
|
||||
|
||||
;
|
||||
|
||||
ExecMessageDefine(MessageClassifyEnum classify, String title, String content) {
|
||||
this.classify = classify;
|
||||
this.type = this.name();
|
||||
this.title = title;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息分类
|
||||
*/
|
||||
private final MessageClassifyEnum classify;
|
||||
|
||||
/**
|
||||
* 消息类型
|
||||
*/
|
||||
private final String type;
|
||||
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
private final String title;
|
||||
|
||||
/**
|
||||
* 内容
|
||||
*/
|
||||
private final String content;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.orion.ops.module.asset.define.message;
|
||||
|
||||
import com.orion.ops.module.infra.define.SystemMessageDefine;
|
||||
import com.orion.ops.module.infra.enums.MessageClassifyEnum;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 上传任务 系统消息定义
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2024/5/14 17:23
|
||||
*/
|
||||
@Getter
|
||||
public enum UploadMessageDefine implements SystemMessageDefine {
|
||||
|
||||
/**
|
||||
* 上传任务部分失败
|
||||
*/
|
||||
UPLOAD_FAILED(MessageClassifyEnum.NOTICE,
|
||||
"批量上传失败",
|
||||
"您在 <sb>${time}</sb> 提交的上传任务中, 有部分主机文件上传失败。点击查看详情 <sb>#${id}</sb> >>>"),
|
||||
|
||||
;
|
||||
|
||||
UploadMessageDefine(MessageClassifyEnum classify, String title, String content) {
|
||||
this.classify = classify;
|
||||
this.type = this.name();
|
||||
this.title = title;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息分类
|
||||
*/
|
||||
private final MessageClassifyEnum classify;
|
||||
|
||||
/**
|
||||
* 消息类型
|
||||
*/
|
||||
private final String type;
|
||||
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
private final String title;
|
||||
|
||||
/**
|
||||
* 内容
|
||||
*/
|
||||
private final String content;
|
||||
|
||||
}
|
||||
@@ -22,7 +22,7 @@ import java.util.List;
|
||||
@Schema(name = "ExecCommandDTO", description = "批量执行启动对象")
|
||||
public class ExecCommandDTO {
|
||||
|
||||
@Schema(description = "hostId")
|
||||
@Schema(description = "logId")
|
||||
private Long logId;
|
||||
|
||||
@Schema(description = "用户id")
|
||||
|
||||
@@ -67,6 +67,9 @@ public abstract class BaseExecCommandHandler implements IExecCommandHandler {
|
||||
|
||||
private CommandExecutor executor;
|
||||
|
||||
@Getter
|
||||
private Integer exitCode;
|
||||
|
||||
private volatile boolean closed;
|
||||
|
||||
private volatile boolean interrupted;
|
||||
@@ -228,6 +231,7 @@ public abstract class BaseExecCommandHandler implements IExecCommandHandler {
|
||||
// 完成
|
||||
updateRecord.setFinishTime(new Date());
|
||||
updateRecord.setExitStatus(executor.getExitCode());
|
||||
this.exitCode = executor.getExitCode();
|
||||
} else if (ExecHostStatusEnum.FAILED.equals(status)) {
|
||||
// 失败
|
||||
updateRecord.setFinishTime(new Date());
|
||||
|
||||
@@ -7,20 +7,29 @@ import com.orion.lang.utils.Booleans;
|
||||
import com.orion.lang.utils.Threads;
|
||||
import com.orion.lang.utils.collect.Lists;
|
||||
import com.orion.lang.utils.io.Streams;
|
||||
import com.orion.lang.utils.time.Dates;
|
||||
import com.orion.net.host.ssh.ExitCode;
|
||||
import com.orion.ops.framework.common.constant.ExtraFieldConst;
|
||||
import com.orion.ops.module.asset.dao.ExecLogDAO;
|
||||
import com.orion.ops.module.asset.define.AssetThreadPools;
|
||||
import com.orion.ops.module.asset.define.config.AppExecLogConfig;
|
||||
import com.orion.ops.module.asset.define.message.ExecMessageDefine;
|
||||
import com.orion.ops.module.asset.entity.domain.ExecLogDO;
|
||||
import com.orion.ops.module.asset.enums.ExecHostStatusEnum;
|
||||
import com.orion.ops.module.asset.enums.ExecStatusEnum;
|
||||
import com.orion.ops.module.asset.handler.host.exec.command.dto.ExecCommandDTO;
|
||||
import com.orion.ops.module.asset.handler.host.exec.command.dto.ExecCommandHostDTO;
|
||||
import com.orion.ops.module.asset.handler.host.exec.command.manager.ExecTaskManager;
|
||||
import com.orion.ops.module.infra.api.SystemMessageApi;
|
||||
import com.orion.ops.module.infra.entity.dto.message.SystemMessageDTO;
|
||||
import com.orion.spring.SpringHolder;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 命令执行任务
|
||||
@@ -38,6 +47,8 @@ public class ExecTaskHandler implements IExecTaskHandler {
|
||||
|
||||
private static final AppExecLogConfig appExecLogConfig = SpringHolder.getBean(AppExecLogConfig.class);
|
||||
|
||||
private static final SystemMessageApi systemMessageApi = SpringHolder.getBean(SystemMessageApi.class);
|
||||
|
||||
private final ExecCommandDTO execCommand;
|
||||
|
||||
private TimeoutChecker<TimeoutEndpoint> timeoutChecker;
|
||||
@@ -45,6 +56,8 @@ public class ExecTaskHandler implements IExecTaskHandler {
|
||||
@Getter
|
||||
private final List<IExecCommandHandler> handlers;
|
||||
|
||||
private Date startTime;
|
||||
|
||||
public ExecTaskHandler(ExecCommandDTO execCommand) {
|
||||
this.execCommand = execCommand;
|
||||
this.handlers = Lists.newList();
|
||||
@@ -56,9 +69,9 @@ public class ExecTaskHandler implements IExecTaskHandler {
|
||||
// 添加任务
|
||||
execTaskManager.addTask(id, this);
|
||||
log.info("ExecTaskHandler.run start id: {}", id);
|
||||
// 更新状态
|
||||
this.updateStatus(ExecStatusEnum.RUNNING);
|
||||
try {
|
||||
// 更新状态
|
||||
this.updateStatus(ExecStatusEnum.RUNNING);
|
||||
// 执行命令
|
||||
this.runHostCommand();
|
||||
// 更新状态-执行完成
|
||||
@@ -69,10 +82,12 @@ public class ExecTaskHandler implements IExecTaskHandler {
|
||||
this.updateStatus(ExecStatusEnum.FAILED);
|
||||
log.error("ExecTaskHandler.run error id: {}", id, e);
|
||||
} finally {
|
||||
// 释放资源
|
||||
Streams.close(this);
|
||||
// 检查是否发送消息
|
||||
this.checkSendMessage();
|
||||
// 移除任务
|
||||
execTaskManager.removeTask(id);
|
||||
// 释放资源
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,6 +97,13 @@ public class ExecTaskHandler implements IExecTaskHandler {
|
||||
handlers.forEach(IExecCommandHandler::interrupt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
log.info("ExecTaskHandler-close id: {}", execCommand.getLogId());
|
||||
Streams.close(timeoutChecker);
|
||||
this.handlers.forEach(Streams::close);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行主机命令
|
||||
*
|
||||
@@ -139,6 +161,7 @@ public class ExecTaskHandler implements IExecTaskHandler {
|
||||
update.setStatus(statusName);
|
||||
if (ExecStatusEnum.RUNNING.equals(status)) {
|
||||
// 执行中
|
||||
this.startTime = new Date();
|
||||
update.setStartTime(new Date());
|
||||
} else if (ExecStatusEnum.COMPLETED.equals(status)) {
|
||||
// 执行完成
|
||||
@@ -151,11 +174,30 @@ public class ExecTaskHandler implements IExecTaskHandler {
|
||||
log.info("ExecTaskHandler-updateStatus finish id: {}, effect: {}", id, effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
log.info("ExecTaskHandler-close id: {}", execCommand.getLogId());
|
||||
Streams.close(timeoutChecker);
|
||||
this.handlers.forEach(Streams::close);
|
||||
/**
|
||||
* 检查是否发送消息
|
||||
*/
|
||||
private void checkSendMessage() {
|
||||
// 检查是否执行失败/exitCode
|
||||
boolean hasError = handlers.stream().anyMatch(s ->
|
||||
ExecHostStatusEnum.FAILED.equals(s.getStatus())
|
||||
|| ExecHostStatusEnum.TIMEOUT.equals(s.getStatus())
|
||||
|| !ExitCode.isSuccess(s.getExitCode()));
|
||||
if (!hasError) {
|
||||
return;
|
||||
}
|
||||
// 参数
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put(ExtraFieldConst.ID, execCommand.getLogId());
|
||||
params.put(ExtraFieldConst.TIME, Dates.format(this.startTime, Dates.MD_HM));
|
||||
SystemMessageDTO message = SystemMessageDTO.builder()
|
||||
.receiverId(execCommand.getUserId())
|
||||
.receiverUsername(execCommand.getUsername())
|
||||
.relKey(String.valueOf(execCommand.getLogId()))
|
||||
.params(params)
|
||||
.build();
|
||||
// 发送
|
||||
systemMessageApi.create(ExecMessageDefine.EXEC_FAILED, message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,6 +31,13 @@ public interface IExecCommandHandler extends Runnable, SafeCloseable {
|
||||
*/
|
||||
ExecHostStatusEnum getStatus();
|
||||
|
||||
/**
|
||||
* 获取退出码
|
||||
*
|
||||
* @return exit code
|
||||
*/
|
||||
Integer getExitCode();
|
||||
|
||||
/**
|
||||
* 获取主机 id
|
||||
*
|
||||
|
||||
@@ -3,10 +3,13 @@ package com.orion.ops.module.asset.handler.host.upload.task;
|
||||
import com.orion.lang.utils.Threads;
|
||||
import com.orion.lang.utils.io.Files1;
|
||||
import com.orion.lang.utils.io.Streams;
|
||||
import com.orion.lang.utils.time.Dates;
|
||||
import com.orion.ops.framework.common.constant.Const;
|
||||
import com.orion.ops.framework.common.constant.ExtraFieldConst;
|
||||
import com.orion.ops.module.asset.dao.UploadTaskDAO;
|
||||
import com.orion.ops.module.asset.dao.UploadTaskFileDAO;
|
||||
import com.orion.ops.module.asset.define.AssetThreadPools;
|
||||
import com.orion.ops.module.asset.define.message.UploadMessageDefine;
|
||||
import com.orion.ops.module.asset.entity.domain.UploadTaskDO;
|
||||
import com.orion.ops.module.asset.entity.domain.UploadTaskFileDO;
|
||||
import com.orion.ops.module.asset.enums.UploadTaskFileStatusEnum;
|
||||
@@ -16,14 +19,13 @@ import com.orion.ops.module.asset.handler.host.upload.manager.FileUploadTaskMana
|
||||
import com.orion.ops.module.asset.handler.host.upload.uploader.FileUploader;
|
||||
import com.orion.ops.module.asset.handler.host.upload.uploader.IFileUploader;
|
||||
import com.orion.ops.module.asset.service.UploadTaskService;
|
||||
import com.orion.ops.module.infra.api.SystemMessageApi;
|
||||
import com.orion.ops.module.infra.entity.dto.message.SystemMessageDTO;
|
||||
import com.orion.spring.SpringHolder;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -42,6 +44,8 @@ public class FileUploadTask implements IFileUploadTask {
|
||||
|
||||
private static final UploadTaskService uploadTaskService = SpringHolder.getBean(UploadTaskService.class);
|
||||
|
||||
private static final SystemMessageApi systemMessageApi = SpringHolder.getBean(SystemMessageApi.class);
|
||||
|
||||
private static final FileUploadTaskManager fileUploadTaskManager = SpringHolder.getBean(FileUploadTaskManager.class);
|
||||
|
||||
private final Long id;
|
||||
@@ -91,6 +95,8 @@ public class FileUploadTask implements IFileUploadTask {
|
||||
} else {
|
||||
this.updateStatus(UploadTaskStatusEnum.FINISHED);
|
||||
}
|
||||
// 检查是否发送消息
|
||||
this.checkSendMessage();
|
||||
// 移除任务
|
||||
fileUploadTaskManager.removeTask(id);
|
||||
// 释放资源
|
||||
@@ -187,4 +193,33 @@ public class FileUploadTask implements IFileUploadTask {
|
||||
uploadTaskDAO.updateById(update);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否发送消息
|
||||
*/
|
||||
private void checkSendMessage() {
|
||||
if (canceled) {
|
||||
return;
|
||||
}
|
||||
// 检查是否上传失败
|
||||
boolean hasError = uploaderList.stream()
|
||||
.map(IFileUploader::getFiles)
|
||||
.flatMap(Collection::stream)
|
||||
.anyMatch(s -> UploadTaskFileStatusEnum.FAILED.name().equals(s.getStatus()));
|
||||
if (!hasError) {
|
||||
return;
|
||||
}
|
||||
// 参数
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put(ExtraFieldConst.ID, record.getId());
|
||||
params.put(ExtraFieldConst.TIME, Dates.format(record.getCreateTime(), Dates.MD_HM));
|
||||
SystemMessageDTO message = SystemMessageDTO.builder()
|
||||
.receiverId(record.getUserId())
|
||||
.receiverUsername(record.getUsername())
|
||||
.relKey(String.valueOf(record.getId()))
|
||||
.params(params)
|
||||
.build();
|
||||
// 发送
|
||||
systemMessageApi.create(UploadMessageDefine.UPLOAD_FAILED, message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.orion.ops.module.infra.api;
|
||||
|
||||
import com.orion.ops.module.infra.define.SystemMessageDefine;
|
||||
import com.orion.ops.module.infra.entity.dto.message.SystemMessageCreateDTO;
|
||||
import com.orion.ops.module.infra.entity.dto.message.SystemMessageDTO;
|
||||
import com.orion.ops.module.infra.enums.MessageClassifyEnum;
|
||||
|
||||
/**
|
||||
@@ -12,6 +14,15 @@ import com.orion.ops.module.infra.enums.MessageClassifyEnum;
|
||||
*/
|
||||
public interface SystemMessageApi {
|
||||
|
||||
/**
|
||||
* 创建系统消息
|
||||
*
|
||||
* @param define define
|
||||
* @param dto dto
|
||||
* @return id
|
||||
*/
|
||||
Long create(SystemMessageDefine define, SystemMessageDTO dto);
|
||||
|
||||
/**
|
||||
* 创建系统消息
|
||||
*
|
||||
@@ -19,6 +30,6 @@ public interface SystemMessageApi {
|
||||
* @param dto dto
|
||||
* @return id
|
||||
*/
|
||||
Long createSystemMessage(MessageClassifyEnum classify, SystemMessageCreateDTO dto);
|
||||
Long create(MessageClassifyEnum classify, SystemMessageCreateDTO dto);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.orion.ops.module.infra.define;
|
||||
|
||||
import com.orion.lang.utils.Strings;
|
||||
import com.orion.ops.module.infra.enums.MessageClassifyEnum;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 系统消息定义
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2024/5/14 17:06
|
||||
*/
|
||||
public interface SystemMessageDefine {
|
||||
|
||||
/**
|
||||
* @return 消息分类
|
||||
*/
|
||||
MessageClassifyEnum getClassify();
|
||||
|
||||
/**
|
||||
* @return 消息类型
|
||||
*/
|
||||
String getType();
|
||||
|
||||
/**
|
||||
* @return 标题
|
||||
*/
|
||||
String getTitle();
|
||||
|
||||
/**
|
||||
* @return 内容
|
||||
*/
|
||||
String getContent();
|
||||
|
||||
/**
|
||||
* 格式化内容
|
||||
*
|
||||
* @param params params
|
||||
* @return content
|
||||
*/
|
||||
default String formatContent(Map<String, Object> params) {
|
||||
return Strings.format(this.getContent(), params);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,6 +27,11 @@ public class SystemMessageCreateDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@NotBlank
|
||||
@Size(max = 10)
|
||||
@Schema(description = "消息分类")
|
||||
private String classify;
|
||||
|
||||
@NotBlank
|
||||
@Size(max = 32)
|
||||
@Schema(description = "消息类型")
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.orion.ops.module.infra.entity.dto.message;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 系统消息 请求业务对象
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.8
|
||||
* @since 2024-5-11 16:29
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(name = "SystemMessageDTO", description = "系统消息 请求业务对象")
|
||||
public class SystemMessageDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@NotBlank
|
||||
@Size(max = 64)
|
||||
@Schema(description = "消息关联")
|
||||
private String relKey;
|
||||
|
||||
@NotNull
|
||||
@Schema(description = "接收人id")
|
||||
private Long receiverId;
|
||||
|
||||
@Schema(description = "接收人用户名")
|
||||
private String receiverUsername;
|
||||
|
||||
@Schema(description = "参数")
|
||||
private Map<String, Object> params;
|
||||
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
package com.orion.ops.module.infra.api.impl;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.orion.ops.framework.common.utils.Valid;
|
||||
import com.orion.ops.module.infra.api.SystemMessageApi;
|
||||
import com.orion.ops.module.infra.convert.SystemMessageProviderConvert;
|
||||
import com.orion.ops.module.infra.define.SystemMessageDefine;
|
||||
import com.orion.ops.module.infra.entity.dto.message.SystemMessageCreateDTO;
|
||||
import com.orion.ops.module.infra.entity.dto.message.SystemMessageDTO;
|
||||
import com.orion.ops.module.infra.entity.request.message.SystemMessageCreateRequest;
|
||||
import com.orion.ops.module.infra.enums.MessageClassifyEnum;
|
||||
import com.orion.ops.module.infra.service.SystemMessageService;
|
||||
@@ -28,12 +29,28 @@ public class SystemMessageApiImpl implements SystemMessageApi {
|
||||
private SystemMessageService systemMessageService;
|
||||
|
||||
@Override
|
||||
public Long createSystemMessage(MessageClassifyEnum classify, SystemMessageCreateDTO dto) {
|
||||
log.info("SystemMessageApi.createSystemMessage dto: {}", JSON.toJSONString(dto));
|
||||
public Long create(SystemMessageDefine define, SystemMessageDTO dto) {
|
||||
Valid.valid(dto);
|
||||
// 转换
|
||||
SystemMessageCreateRequest request = SystemMessageCreateRequest.builder()
|
||||
.classify(define.getClassify().name())
|
||||
.type(define.getType())
|
||||
.title(define.getTitle())
|
||||
.content(define.formatContent(dto.getParams()))
|
||||
.relKey(dto.getRelKey())
|
||||
.receiverId(dto.getReceiverId())
|
||||
.receiverUsername(dto.getReceiverUsername())
|
||||
.build();
|
||||
// 创建
|
||||
return systemMessageService.createSystemMessage(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long create(MessageClassifyEnum classify, SystemMessageCreateDTO dto) {
|
||||
dto.setClassify(classify.name());
|
||||
Valid.valid(dto);
|
||||
// 转换
|
||||
SystemMessageCreateRequest request = SystemMessageProviderConvert.MAPPER.toRequest(dto);
|
||||
request.setClassify(classify.name());
|
||||
// 创建
|
||||
return systemMessageService.createSystemMessage(request);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.orion.ops.module.infra.service.impl;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.orion.lang.function.Functions;
|
||||
import com.orion.lang.utils.Booleans;
|
||||
@@ -44,6 +45,7 @@ public class SystemMessageServiceImpl implements SystemMessageService {
|
||||
|
||||
@Override
|
||||
public Long createSystemMessage(SystemMessageCreateRequest request) {
|
||||
log.info("SystemMessageService.createSystemMessage request: {}", JSON.toJSONString(request));
|
||||
// 设置接收人用户名
|
||||
if (request.getReceiverUsername() == null) {
|
||||
Optional.ofNullable(request.getReceiverId())
|
||||
|
||||
@@ -99,7 +99,8 @@
|
||||
position="br"
|
||||
:show-arrow="false"
|
||||
:popup-style="{ marginLeft: '198px' }"
|
||||
:content-style="{ padding: 0, width: '498px' }">
|
||||
:content-style="{ padding: 0, width: '428px' }"
|
||||
@hide="pullHasUnreadMessage">
|
||||
<div ref="messageRef" class="ref-btn" />
|
||||
<template #content>
|
||||
<message-box />
|
||||
@@ -310,10 +311,6 @@
|
||||
|
||||
// 获取是否有未读的消息
|
||||
const pullHasUnreadMessage = () => {
|
||||
// 有未读的消息直接返回
|
||||
if (messageCount.value) {
|
||||
return;
|
||||
}
|
||||
// 查询
|
||||
checkHasUnreadMessage().then(({ data }) => {
|
||||
messageCount.value = data ? 1 : 0;
|
||||
|
||||
@@ -26,13 +26,6 @@
|
||||
checked-text="未读"
|
||||
unchecked-text="全部"
|
||||
@change="reloadAllMessage" />
|
||||
<!-- 全部已读 -->
|
||||
<a-button class="header-button"
|
||||
type="text"
|
||||
size="small"
|
||||
@click="setAllRead">
|
||||
全部已读
|
||||
</a-button>
|
||||
<!-- 清空 -->
|
||||
<a-button class="header-button"
|
||||
type="text"
|
||||
@@ -40,6 +33,13 @@
|
||||
@click="clearAllMessage">
|
||||
清空
|
||||
</a-button>
|
||||
<!-- 全部已读 -->
|
||||
<a-button class="header-button"
|
||||
type="text"
|
||||
size="small"
|
||||
@click="setAllRead">
|
||||
全部已读
|
||||
</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
</a-tabs>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<!-- 加载中 -->
|
||||
<a-skeleton class="skeleton-wrapper" :animation="true">
|
||||
<a-skeleton-line :rows="3"
|
||||
:line-height="86"
|
||||
:line-height="96"
|
||||
:line-spacing="8" />
|
||||
</a-skeleton>
|
||||
</div>
|
||||
@@ -56,17 +56,21 @@
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 文本 -->
|
||||
<!-- 内容 -->
|
||||
<div v-html="message.contentHtml"
|
||||
class="message-item-content text-ellipsis"
|
||||
class="message-item-content"
|
||||
:title="message.content" />
|
||||
<!-- 时间 -->
|
||||
<div class="message-item-time">
|
||||
{{ dateFormat(new Date(message.createTime))}}
|
||||
</div>
|
||||
</div>
|
||||
<!-- 加载中 -->
|
||||
<a-skeleton v-if="fetchLoading"
|
||||
class="skeleton-wrapper"
|
||||
:animation="true">
|
||||
<a-skeleton-line :rows="3"
|
||||
:line-height="86"
|
||||
:line-height="96"
|
||||
:line-spacing="8" />
|
||||
</a-skeleton>
|
||||
<!-- 加载更多 -->
|
||||
@@ -92,6 +96,7 @@
|
||||
import type { MessageRecordResponse } from '@/api/system/message';
|
||||
import { MessageStatus, messageTypeKey } from './const';
|
||||
import { useDictStore } from '@/store';
|
||||
import { dateFormat } from '@/utils';
|
||||
|
||||
const emits = defineEmits(['load', 'click', 'view', 'delete']);
|
||||
const props = defineProps<{
|
||||
@@ -107,7 +112,6 @@
|
||||
|
||||
<style lang="less" scoped>
|
||||
@gap: 8px;
|
||||
@message-height: 86px;
|
||||
@actions-width: 82px;
|
||||
|
||||
.skeleton-wrapper {
|
||||
@@ -116,7 +120,7 @@
|
||||
|
||||
.message-list-container {
|
||||
width: 100%;
|
||||
height: 344px;
|
||||
height: 338px;
|
||||
display: block;
|
||||
|
||||
.message-list-wrapper {
|
||||
@@ -133,17 +137,17 @@
|
||||
}
|
||||
|
||||
.message-item {
|
||||
height: @message-height;
|
||||
padding: 16px 20px;
|
||||
padding: 12px 20px;
|
||||
border-bottom: 1px solid var(--color-neutral-3);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
font-size: 14px;
|
||||
color: var(--color-text-1);
|
||||
cursor: pointer;
|
||||
transition: all .2s;
|
||||
|
||||
&-title {
|
||||
height: 22px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
@@ -151,9 +155,9 @@
|
||||
&-text {
|
||||
width: calc(100% - @actions-width - @gap);
|
||||
display: block;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
text-overflow: clip;
|
||||
color: var(--color-text-1);
|
||||
}
|
||||
|
||||
&-status {
|
||||
@@ -181,9 +185,17 @@
|
||||
|
||||
&-content {
|
||||
display: block;
|
||||
padding-bottom: 2px;
|
||||
color: var(--color-text-1);
|
||||
text-overflow: clip;
|
||||
margin-top: 4px;
|
||||
font-size: 12px;
|
||||
color: var(--color-text-2);
|
||||
}
|
||||
|
||||
&-time {
|
||||
height: 18px;
|
||||
margin-top: 4px;
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
color: var(--color-text-2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,7 +213,7 @@
|
||||
}
|
||||
|
||||
.message-item-read {
|
||||
.message-item-title-text, .message-item-title-status, .message-item-content {
|
||||
.message-item-title-text, .message-item-title-status, .message-item-content, .message-item-time {
|
||||
opacity: .65;
|
||||
}
|
||||
}
|
||||
@@ -210,10 +222,6 @@
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
.arco-scrollbar-track-direction-horizontal {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -3,12 +3,11 @@
|
||||
title-align="start"
|
||||
:title="record.title"
|
||||
:top="80"
|
||||
:width="720"
|
||||
:align-center="false"
|
||||
:unmount-on-close="true"
|
||||
ok-text="删除"
|
||||
:hide-cancel="true"
|
||||
:ok-button-props="{ status: 'danger' }"
|
||||
:ok-button-props="{ status: 'danger', size: 'small' }"
|
||||
:body-style="{ padding: '20px' }"
|
||||
@ok="emits('delete', record)">
|
||||
<div class="content" v-html="record.contentHtml" />
|
||||
@@ -45,5 +44,6 @@
|
||||
<style lang="less" scoped>
|
||||
.content {
|
||||
font-size: 16px;
|
||||
color: var(--color-text-2);
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user