feat: 消息中心

dev_1.0.2
zhanglei 2026-07-16 10:28:57 +08:00
parent b78511f11d
commit 7f7e28b3ea
17 changed files with 635 additions and 0 deletions

View File

@ -0,0 +1,66 @@
package org.qinan.safetyeval.adapter.web;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.qinan.safetyeval.client.api.SafetyMessageApi;
import org.qinan.safetyeval.client.co.SafetyMessageCO;
import org.qinan.safetyeval.client.dto.*;
import org.qinan.safetyeval.infrastructure.dataobject.base.Req;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
/**
* Controller
*
* @author safety-eval
*/
@Slf4j
@Api(tags = "消息中心")
@RestController
@RequestMapping("/safetyEval/safetyMessage")
public class SafetyMessageController {
@Resource
private SafetyMessageApi safetyMessageApi;
@ApiOperation("新增消息")
@PostMapping("/save")
public SingleResponse<SafetyMessageCO> add(@Validated @RequestBody SafetyMessageAddCmd cmd) {
return safetyMessageApi.add(cmd);
}
@ApiOperation("查询消息详情")
@GetMapping("/get")
public SingleResponse<SafetyMessageCO> get(@ApiParam("主键ID") @RequestParam Long id) {
return safetyMessageApi.get(id);
}
@ApiOperation("修改消息")
@PostMapping("/modify")
public SingleResponse<SafetyMessageCO> modify(@Validated @RequestBody SafetyMessageModifyCmd cmd) {
return safetyMessageApi.modify(cmd);
}
@ApiOperation("批量标为已读")
@PostMapping("/batchMarkedAsRead")
public SingleResponse<Boolean> batchMarkedAsRead(@ApiParam("主键IDj集合") @RequestBody Req<List<Long>> req) {
return safetyMessageApi.batchMarkedAsRead(req.getData());
}
@ApiOperation("删除消息")
@PostMapping("/delete")
public SingleResponse<Void> delete(@ApiParam("主键ID") @RequestBody Req<Long> req) {
return safetyMessageApi.delete(req.getData());
}
@ApiOperation("分页查询消息")
@GetMapping("/page")
public PageResponse<SafetyMessageCO> page(@Validated SafetyMessagePageQuery query) {
return safetyMessageApi.page(query);
}
}

View File

@ -0,0 +1,33 @@
package org.qinan.safetyeval.app.convertor;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.qinan.safetyeval.client.co.SafetyMessageCO;
import org.qinan.safetyeval.client.dto.SafetyMessageAddCmd;
import org.qinan.safetyeval.client.dto.SafetyMessageModifyCmd;
import org.qinan.safetyeval.client.dto.SafetyMessagePageQuery;
import org.qinan.safetyeval.domain.entity.SafetyMessageEntity;
import org.qinan.safetyeval.domain.query.SafetyMessageQuery;
import java.util.List;
/**
*
*
* @author safety-eval
*/
@Mapper(componentModel = "spring")
public interface SafetyMessageCmdConvertor {
SafetyMessageEntity convertAddCmdToE(SafetyMessageAddCmd cmd);
SafetyMessageEntity convertModifyCmdToE(SafetyMessageModifyCmd cmd);
@Mapping(target = "pageNum", source = "current")
@Mapping(target = "pageSize", source = "size")
SafetyMessageQuery convertPageQueryToQ(SafetyMessagePageQuery query);
SafetyMessageCO convertEToCO(SafetyMessageEntity entity);
List<SafetyMessageCO> convertEListToCOList(List<SafetyMessageEntity> list);
}

View File

@ -0,0 +1,86 @@
package org.qinan.safetyeval.app.executor;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.qinan.safetyeval.app.convertor.SafetyMessageCmdConvertor;
import org.qinan.safetyeval.client.api.SafetyMessageApi;
import org.qinan.safetyeval.client.co.SafetyMessageCO;
import org.qinan.safetyeval.client.dto.PageResponse;
import org.qinan.safetyeval.client.dto.SafetyMessageAddCmd;
import org.qinan.safetyeval.client.dto.SafetyMessageModifyCmd;
import org.qinan.safetyeval.client.dto.SafetyMessagePageQuery;
import org.qinan.safetyeval.client.dto.SingleResponse;
import org.qinan.safetyeval.domain.entity.SafetyMessageEntity;
import org.qinan.safetyeval.domain.query.PageResult;
import org.qinan.safetyeval.domain.query.SafetyMessageQuery;
import org.qinan.safetyeval.domain.service.SafetyMessageDomainService;
import org.qinan.safetyeval.infrastructure.adapter.ThreadLocalUserInfoAdapter;
import org.qinan.safetyeval.infrastructure.dataobject.SafetyMessageDO;
import org.qinan.safetyeval.infrastructure.mapper.SafetyMessageMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
* App
*
* @author safety-eval
*/
@Service
public class SafetyMessageExecutor implements SafetyMessageApi {
@Resource
private SafetyMessageDomainService safetyMessageDomainService;
@Resource
private SafetyMessageCmdConvertor safetyMessageCmdConvertor;
@Autowired
private SafetyMessageMapper safetyMessageMapper;
@Override
public SingleResponse<SafetyMessageCO> add(SafetyMessageAddCmd cmd) {
SafetyMessageEntity entity = safetyMessageCmdConvertor.convertAddCmdToE(cmd);
SafetyMessageEntity result = safetyMessageDomainService.add(entity);
return SingleResponse.success(safetyMessageCmdConvertor.convertEToCO(result));
}
@Override
public SingleResponse<SafetyMessageCO> get(Long id) {
SafetyMessageEntity entity = safetyMessageDomainService.get(id);
return SingleResponse.success(safetyMessageCmdConvertor.convertEToCO(entity));
}
@Override
public SingleResponse<SafetyMessageCO> modify(SafetyMessageModifyCmd cmd) {
SafetyMessageEntity entity = safetyMessageCmdConvertor.convertModifyCmdToE(cmd);
SafetyMessageEntity result = safetyMessageDomainService.modify(entity);
return SingleResponse.success(safetyMessageCmdConvertor.convertEToCO(result));
}
@Override
public SingleResponse<Void> delete(Long id) {
safetyMessageDomainService.delete(id);
return SingleResponse.success();
}
@Override
public PageResponse<SafetyMessageCO> page(SafetyMessagePageQuery query) {
SafetyMessageQuery domainQuery = safetyMessageCmdConvertor.convertPageQueryToQ(query);
if (domainQuery.getOrgId() == null) {
domainQuery.setOrgId(ThreadLocalUserInfoAdapter.get());
}
PageResult<SafetyMessageEntity> pageResult = safetyMessageDomainService.page(domainQuery);
return PageResponse.of(
safetyMessageCmdConvertor.convertEListToCOList(pageResult.getRecords()),
pageResult.getTotal());
}
@Override
public SingleResponse<Boolean> batchMarkedAsRead(List<Long> data) {
safetyMessageMapper.update(new LambdaUpdateWrapper<SafetyMessageDO>()
.in(SafetyMessageDO::getId, data)
.set(SafetyMessageDO::getSendState, 1)
);
return SingleResponse.success(true);
}
}

View File

@ -0,0 +1,30 @@
package org.qinan.safetyeval.client.api;
import org.qinan.safetyeval.client.co.SafetyMessageCO;
import org.qinan.safetyeval.client.dto.PageResponse;
import org.qinan.safetyeval.client.dto.SafetyMessageAddCmd;
import org.qinan.safetyeval.client.dto.SafetyMessageModifyCmd;
import org.qinan.safetyeval.client.dto.SafetyMessagePageQuery;
import org.qinan.safetyeval.client.dto.SingleResponse;
import java.util.List;
/**
* Client
*
* @author safety-eval
*/
public interface SafetyMessageApi {
SingleResponse<SafetyMessageCO> add(SafetyMessageAddCmd cmd);
SingleResponse<SafetyMessageCO> get(Long id);
SingleResponse<SafetyMessageCO> modify(SafetyMessageModifyCmd cmd);
SingleResponse<Void> delete(Long id);
PageResponse<SafetyMessageCO> page(SafetyMessagePageQuery query);
SingleResponse<Boolean> batchMarkedAsRead(List<Long> data);
}

View File

@ -0,0 +1,42 @@
package org.qinan.safetyeval.client.co;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.time.LocalDateTime;
/**
* CO
*
* @author safety-eval
*/
@Data
public class SafetyMessageCO {
@ApiModelProperty(value = "主键ID")
private Long id;
@ApiModelProperty(value = "机构id")
private Long orgId;
@ApiModelProperty(value = "发送者姓名")
private String sendName;
@ApiModelProperty(value = "发送者id")
private Long sendId;
@ApiModelProperty(value = "发送类型")
private String sendType;
@ApiModelProperty(value = "发送内容: json格式(暂定: {\"content\":\"text\"})}")
private String sendContent;
@ApiModelProperty(value = "接收人id")
private Long receiveId;
@ApiModelProperty(value = "发送状态 0-未读, 1-已读")
private Integer sendState;
@ApiModelProperty(value = "创建时间")
private LocalDateTime createTime;
}

View File

@ -0,0 +1,34 @@
package org.qinan.safetyeval.client.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
*
*
* @author safety-eval
*/
@Data
public class SafetyMessageAddCmd {
@ApiModelProperty(value = "机构id")
private Long orgId;
@ApiModelProperty(value = "发送者姓名")
private String sendName;
@ApiModelProperty(value = "发送者id")
private Long sendId;
@ApiModelProperty(value = "发送类型")
private String sendType;
@ApiModelProperty(value = "发送内容: json格式")
private String sendContent;
@ApiModelProperty(value = "接收人id")
private Long receiveId;
@ApiModelProperty(value = "发送状态 0-未读, 1-已读")
private Integer sendState;
}

View File

@ -0,0 +1,37 @@
package org.qinan.safetyeval.client.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
*
*
* @author safety-eval
*/
@Data
public class SafetyMessageModifyCmd {
@ApiModelProperty(value = "主键ID")
private Long id;
@ApiModelProperty(value = "机构id")
private Long orgId;
@ApiModelProperty(value = "发送者姓名")
private String sendName;
@ApiModelProperty(value = "发送者id")
private Long sendId;
@ApiModelProperty(value = "发送类型")
private String sendType;
@ApiModelProperty(value = "发送内容: json格式")
private String sendContent;
@ApiModelProperty(value = "接收人id")
private Long receiveId;
@ApiModelProperty(value = "发送状态 0-未读, 1-已读")
private Integer sendState;
}

View File

@ -0,0 +1,27 @@
package org.qinan.safetyeval.client.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
*
*
* @author safety-eval
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class SafetyMessagePageQuery extends BasePageQuery {
@ApiModelProperty(value = "机构id")
private Long orgId;
@ApiModelProperty(value = "接收人id")
private Long receiveId;
@ApiModelProperty(value = "发送类型")
private String sendType;
@ApiModelProperty(value = "发送状态 0-未读, 1-已读")
private Integer sendState;
}

View File

@ -0,0 +1,24 @@
package org.qinan.safetyeval.domain.entity;
import lombok.Data;
import java.time.LocalDateTime;
/**
*
*
* @author safety-eval
*/
@Data
public class SafetyMessageEntity {
private Long id;
private Long orgId;
private String sendName;
private Long sendId;
private String sendType;
private String sendContent;
private Long receiveId;
private Integer sendState;
private LocalDateTime createTime;
}

View File

@ -106,6 +106,8 @@ public enum ErrorCode {
GBS_USER_ERROR("04-01-001", "gbs用户未登录"), GBS_USER_ERROR("04-01-001", "gbs用户未登录"),
GBS_USER_SYNC_ERROR("04-01-002", "gbs用户同步错误"), GBS_USER_SYNC_ERROR("04-01-002", "gbs用户同步错误"),
// ---- 消息中心 ----
SAFETY_MESSAGE_NOT_FOUND("05-01-001", "消息不存在"),
/** /**
* *

View File

@ -0,0 +1,23 @@
package org.qinan.safetyeval.domain.gateway;
import org.qinan.safetyeval.domain.entity.SafetyMessageEntity;
import org.qinan.safetyeval.domain.query.PageResult;
import org.qinan.safetyeval.domain.query.SafetyMessageQuery;
/**
* Gateway
*
* @author safety-eval
*/
public interface SafetyMessageGateway {
SafetyMessageEntity save(SafetyMessageEntity entity);
SafetyMessageEntity get(Long id);
SafetyMessageEntity modify(SafetyMessageEntity entity);
void delete(Long id);
PageResult<SafetyMessageEntity> page(SafetyMessageQuery query);
}

View File

@ -0,0 +1,19 @@
package org.qinan.safetyeval.domain.query;
import lombok.Data;
/**
*
*
* @author safety-eval
*/
@Data
public class SafetyMessageQuery {
private Long pageNum;
private Long pageSize;
private Long orgId;
private Long receiveId;
private String sendType;
private Integer sendState;
}

View File

@ -0,0 +1,58 @@
package org.qinan.safetyeval.domain.service;
import org.qinan.safetyeval.domain.entity.SafetyMessageEntity;
import org.qinan.safetyeval.domain.exception.BizException;
import org.qinan.safetyeval.domain.exception.ErrorCode;
import org.qinan.safetyeval.domain.gateway.SafetyMessageGateway;
import org.qinan.safetyeval.domain.query.PageResult;
import org.qinan.safetyeval.domain.query.SafetyMessageQuery;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
*
*
* @author safety-eval
*/
@Service
public class SafetyMessageDomainService {
@Resource
private SafetyMessageGateway safetyMessageGateway;
public SafetyMessageEntity add(SafetyMessageEntity entity) {
if (entity.getSendState() == null) {
entity.setSendState(0);
}
return safetyMessageGateway.save(entity);
}
public SafetyMessageEntity get(Long id) {
SafetyMessageEntity entity = safetyMessageGateway.get(id);
if (entity == null) {
throw new BizException(ErrorCode.SAFETY_MESSAGE_NOT_FOUND);
}
return entity;
}
public SafetyMessageEntity modify(SafetyMessageEntity entity) {
SafetyMessageEntity existing = safetyMessageGateway.get(entity.getId());
if (existing == null) {
throw new BizException(ErrorCode.SAFETY_MESSAGE_NOT_FOUND);
}
return safetyMessageGateway.modify(entity);
}
public void delete(Long id) {
SafetyMessageEntity existing = safetyMessageGateway.get(id);
if (existing == null) {
throw new BizException(ErrorCode.SAFETY_MESSAGE_NOT_FOUND);
}
safetyMessageGateway.delete(id);
}
public PageResult<SafetyMessageEntity> page(SafetyMessageQuery query) {
return safetyMessageGateway.page(query);
}
}

View File

@ -0,0 +1,22 @@
package org.qinan.safetyeval.infrastructure.convertor;
import org.mapstruct.Mapper;
import org.qinan.safetyeval.domain.entity.SafetyMessageEntity;
import org.qinan.safetyeval.infrastructure.dataobject.SafetyMessageDO;
import java.util.List;
/**
* DO
*
* @author safety-eval
*/
@Mapper(componentModel = "spring")
public interface SafetyMessageDoConvertor {
SafetyMessageDO convertEToDo(SafetyMessageEntity entity);
SafetyMessageEntity convertDoToE(SafetyMessageDO dataObject);
List<SafetyMessageEntity> convertDoListToEList(List<SafetyMessageDO> list);
}

View File

@ -0,0 +1,37 @@
package org.qinan.safetyeval.infrastructure.dataobject;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
/**
*
*
* @author safety-eval
*/
@Data
@TableName("safety_message")
public class SafetyMessageDO {
private Long id;
private Long orgId;
private String sendName;
private Long sendId;
private String sendType;
private String sendContent;
private Long receiveId;
private Integer sendState;
private String deleteEnum;
private String remarks;
private String createName;
private String updateName;
private Long tenantId;
private Integer version;
private LocalDateTime createTime;
private LocalDateTime updateTime;
private Long createId;
private Long updateId;
private String env;
}

View File

@ -0,0 +1,86 @@
package org.qinan.safetyeval.infrastructure.gatewayimpl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.qinan.safetyeval.domain.entity.SafetyMessageEntity;
import org.qinan.safetyeval.domain.gateway.SafetyMessageGateway;
import org.qinan.safetyeval.domain.query.PageResult;
import org.qinan.safetyeval.domain.query.SafetyMessageQuery;
import org.qinan.safetyeval.infrastructure.convertor.SafetyMessageDoConvertor;
import org.qinan.safetyeval.infrastructure.dataobject.SafetyMessageDO;
import org.qinan.safetyeval.infrastructure.mapper.SafetyMessageMapper;
import org.qinan.safetyeval.infrastructure.support.InsertFieldDefaults;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
/**
* Gateway
*
* @author safety-eval
*/
@Component
public class SafetyMessageGatewayImpl implements SafetyMessageGateway {
@Resource
private SafetyMessageMapper safetyMessageMapper;
@Resource
private SafetyMessageDoConvertor safetyMessageDoConvertor;
@Override
public SafetyMessageEntity save(SafetyMessageEntity entity) {
SafetyMessageDO dataObject = safetyMessageDoConvertor.convertEToDo(entity);
InsertFieldDefaults.apply(dataObject);
safetyMessageMapper.insert(dataObject);
return safetyMessageDoConvertor.convertDoToE(dataObject);
}
@Override
public SafetyMessageEntity get(Long id) {
SafetyMessageDO dataObject = safetyMessageMapper.selectById(id);
return safetyMessageDoConvertor.convertDoToE(dataObject);
}
@Override
public SafetyMessageEntity modify(SafetyMessageEntity entity) {
SafetyMessageDO dataObject = safetyMessageDoConvertor.convertEToDo(entity);
dataObject.setId(entity.getId());
InsertFieldDefaults.applyForUpdate(dataObject);
safetyMessageMapper.updateById(dataObject);
return get(entity.getId());
}
@Override
public void delete(Long id) {
safetyMessageMapper.deleteById(id);
}
@Override
public PageResult<SafetyMessageEntity> page(SafetyMessageQuery query) {
LambdaQueryWrapper<SafetyMessageDO> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SafetyMessageDO::getDeleteEnum, "false");
if (query.getOrgId() != null) {
wrapper.eq(SafetyMessageDO::getOrgId, query.getOrgId());
}
if (query.getReceiveId() != null) {
wrapper.eq(SafetyMessageDO::getReceiveId, query.getReceiveId());
}
if (StringUtils.hasText(query.getSendType())) {
wrapper.eq(SafetyMessageDO::getSendType, query.getSendType());
}
if (query.getSendState() != null) {
wrapper.eq(SafetyMessageDO::getSendState, query.getSendState());
}
wrapper.orderByDesc(SafetyMessageDO::getCreateTime);
Page<SafetyMessageDO> page = new Page<>(query.getPageNum(), query.getPageSize());
IPage<SafetyMessageDO> result = safetyMessageMapper.selectPage(page, wrapper);
return PageResult.of(
safetyMessageDoConvertor.convertDoListToEList(result.getRecords()),
result.getTotal(),
result.getCurrent(),
result.getSize());
}
}

View File

@ -0,0 +1,9 @@
package org.qinan.safetyeval.infrastructure.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.qinan.safetyeval.infrastructure.dataobject.SafetyMessageDO;
@Mapper
public interface SafetyMessageMapper extends BaseMapper<SafetyMessageDO> {
}