add internal notify

This commit is contained in:
Timi
2026-08-21 01:38:51 +08:00
parent e3ef3e5275
commit 31c583eeb5
8 changed files with 155 additions and 10 deletions
@@ -1,15 +1,20 @@
package com.imyeyu.api.modules.common.controller;
import com.fasterxml.jackson.annotation.JsonView;
import com.imyeyu.api.annotation.RequireCorePermission;
import com.imyeyu.api.bean.CorePermissionCode;
import com.imyeyu.api.modules.common.entity.Notify;
import com.imyeyu.api.modules.common.entity.NotifyDetail;
import com.imyeyu.api.modules.common.service.NotifyDetailService;
import com.imyeyu.api.modules.common.service.NotifyService;
import com.imyeyu.api.modules.user.entity.User;
import com.imyeyu.api.modules.user.service.UserLoginService;
import com.imyeyu.api.modules.user.service.UserService;
import com.imyeyu.java.TimiJava;
import com.imyeyu.spring.annotation.RequiredToken;
import com.imyeyu.spring.bean.Page;
import com.imyeyu.spring.bean.PageResult;
import com.imyeyu.spring.util.ResponseView;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@@ -17,6 +22,12 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/// 通知接口
///
/// @author 夜雨
@@ -26,11 +37,10 @@ import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/notify")
public class NotifyController {
private final UserService userService;
private final NotifyService service;
private final NotifyDetailService detailService;
private final UserLoginService userLoginService;
private final NotifyDetailService detailService;
/// 创建通知,同时创建通知详情
///
@@ -48,13 +58,28 @@ public class NotifyController {
///
/// @param id 通知 ID
/// @return 通知及通知详情
@JsonView(ResponseView.Public.class)
@RequireCorePermission(CorePermissionCode.NOTIFY_READ)
@RequiredToken
@PostMapping("/detail")
@RequestMapping("/detail")
public Notify detail(@RequestParam String id) {
Notify notify = service.get(id);
if (notify != null) {
notify.setDetailList(detailService.listByNotifyId(id));
{
List<NotifyDetail> detailList = detailService.listByNotifyId(id);
Set<String> userIdSet = detailList.stream()
.filter(item -> item.getMsgType() == NotifyDetail.MsgType.INTERNAL)
.flatMap(item -> Stream.of(item.getSendFrom(), item.getSendTo()))
.collect(Collectors.toSet());
Map<String, User> userMap = userService.mapByIdList(userIdSet);
for (NotifyDetail detail : detailList) {
if (TimiJava.isNotEmpty(detail.getSendFrom())) {
detail.setFromUser(userMap.get(detail.getSendFrom()));
}
if (TimiJava.isNotEmpty(detail.getSendTo())) {
detail.setToUser(userMap.get(detail.getSendTo()));
}
}
notify.setDetailList(detailList);
}
return notify;
}
@@ -94,6 +119,31 @@ public class NotifyController {
return detailService.pageInternalByUserId(page, userLoginService.getRequireLoginUserId(), unreadOnly);
}
@JsonView(ResponseView.Public.class)
@RequireCorePermission(CorePermissionCode.NOTIFY_READ)
@RequiredToken
@PostMapping("/internal/detail")
public NotifyDetail internalDetail(@RequestParam String id) {
NotifyDetail detail = detailService.getInternalByUserId(id, userLoginService.getRequireLoginUserId());
if (TimiJava.isNotEmpty(detail.getSendFrom())) {
detail.setFromUser(userService.get(detail.getSendFrom()));
}
if (TimiJava.isNotEmpty(detail.getSendTo())) {
detail.setToUser(userService.get(detail.getSendTo()));
}
return detail;
}
/// 删除当前用户的一条站内通知
///
/// @param id 通知详情 ID
@RequireCorePermission(CorePermissionCode.NOTIFY_READ)
@RequiredToken
@PostMapping("/internal/delete")
public void deleteInternal(@RequestParam String id) {
detailService.deleteInternalByUserId(id, userLoginService.getRequireLoginUserId());
}
/// 查询当前用户未读通知数量
///
/// @return 未读通知数量
@@ -52,6 +52,19 @@ public class Article extends UUIDEntity implements SettingSupport {
TIP_TAP
}
/// 文章状态
public enum Status {
/// 草稿
DART,
/// 正常
NORMAL,
/// 隐藏
HIDDEN
}
/** 业务类型 */
protected BizType bizType;
@@ -61,8 +74,8 @@ public class Article extends UUIDEntity implements SettingSupport {
/** 标题 */
protected String title;
/** 摘要 */
protected String digest;
/** 描述 */
protected String description;
/** 正文类型 */
protected ContentType contentType;
@@ -77,6 +90,9 @@ public class Article extends UUIDEntity implements SettingSupport {
/** 喜欢数量 */
protected Integer likes;
/** 文章状态 */
protected Status status;
@Transient
protected List<Setting> settingList;
@@ -1,13 +1,16 @@
package com.imyeyu.api.modules.common.entity;
import com.fasterxml.jackson.annotation.JsonView;
import com.imyeyu.api.TimiServerAPI;
import com.imyeyu.api.modules.common.service.BaseQueueService;
import com.imyeyu.api.modules.common.service.HTTPQueueService;
import com.imyeyu.api.modules.common.service.MailQueueService;
import com.imyeyu.api.modules.common.service.SmsQueueService;
import com.imyeyu.api.modules.common.service.WechatQueueService;
import com.imyeyu.api.modules.user.entity.User;
import com.imyeyu.spring.annotation.table.Transient;
import com.imyeyu.spring.entity.UUIDEntity;
import com.imyeyu.spring.util.ResponseView;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -79,47 +82,67 @@ public class NotifyDetail extends UUIDEntity {
}
/** 所属通知 ID */
@JsonView(ResponseView.Public.class)
private String notifyId;
/** 消息类型 */
@JsonView(ResponseView.Public.class)
private MsgType msgType;
/** 模板 ID */
@JsonView(ResponseView.Admin.class)
private String templateId;
/** 标题 */
@JsonView(ResponseView.Public.class)
private String subject;
/** 内容 */
@JsonView(ResponseView.Public.class)
private String data;
/** 参数 */
@JsonView(ResponseView.Public.class)
private String args;
/** 发送来源 */
@JsonView(ResponseView.Public.class)
private String sendFrom;
/** 发送去向 */
@JsonView(ResponseView.Public.class)
private String sendTo;
/** 发送时间 */
@JsonView(ResponseView.Public.class)
private Long sendAt;
/** 重试计数 */
@JsonView(ResponseView.Admin.class)
private Integer retry;
/** 超时时间 */
@JsonView(ResponseView.Admin.class)
private Long timeoutAt;
/** 结果描述 */
@JsonView(ResponseView.Admin.class)
private String resultDesc;
/** 状态 */
@JsonView(ResponseView.Public.class)
private Status status;
/** 已读时间,站内通知未读时为空 */
@JsonView(ResponseView.Public.class)
private Long readAt;
@Transient
protected Notify notify;
@Transient
protected User fromUser;
@Transient
protected User toUser;
}
@@ -36,6 +36,10 @@ public interface NotifyDetailMapper extends BaseMapper<NotifyDetail, String> {
@Select("SELECT * FROM `notify_detail` WHERE `id` = #{detailId} AND `msg_type` = 'INTERNAL' AND `send_to` = #{userId} " + NOT_DELETE + " LIMIT 1")
NotifyDetail selectSiteByIdAndUserId(@Param("detailId") String detailId, @Param("userId") String userId);
/** 删除用户的站内通知 */
@Update("UPDATE `notify_detail` SET `deleted_at` = " + UNIX_TIME + ", `updated_at` = " + UNIX_TIME + " WHERE `id` = #{detailId} AND `msg_type` = 'INTERNAL' AND `send_to` = #{userId} " + NOT_DELETE)
int deleteSiteByIdAndUserId(@Param("detailId") String detailId, @Param("userId") String userId);
/** 标记站内通知已读 */
@Update("UPDATE `notify_detail` SET `read_at` = #{readAt}, `updated_at` = " + UNIX_TIME + " WHERE `id` = #{detailId} AND `msg_type` = 'INTERNAL' AND `send_to` = #{userId} AND `read_at` IS NULL " + NOT_DELETE)
int markSiteRead(@Param("detailId") String detailId, @Param("userId") String userId, @Param("readAt") long readAt);
@@ -34,6 +34,19 @@ public interface NotifyDetailService extends BaseService<NotifyDetail, String> {
/// @return 站内通知分页结果
PageResult<NotifyDetail> pageInternalByUserId(Page<NotifyDetail> page, String userId, boolean unreadOnly);
/// 查询当前用户拥有的站内通知详情
///
/// @param detailId 通知详情 ID
/// @param userId 用户 ID
/// @return 通知详情
NotifyDetail getInternalByUserId(String detailId, String userId);
/// 删除当前用户拥有的站内通知详情
///
/// @param detailId 通知详情 ID
/// @param userId 用户 ID
void deleteInternalByUserId(String detailId, String userId);
/// 查询用户未读站内通知数量
///
/// @param userId 用户 ID
@@ -141,6 +141,33 @@ public class NotifyDetailServiceImplement extends AbstractEntityService<NotifyDe
return result;
}
/// 查询当前用户拥有的站内通知详情
///
/// @param detailId 通知详情 ID
/// @param userId 用户 ID
/// @return 通知详情
@Override
public NotifyDetail getInternalByUserId(String detailId, String userId) {
TimiException.required(detailId, "未找到通知详情 ID");
TimiException.required(userId, "未找到用户 ID");
NotifyDetail detail = mapper.selectSiteByIdAndUserId(detailId, userId);
TimiException.required(detail, "未找到站内通知");
return detail;
}
/// 删除当前用户拥有的站内通知详情
///
/// @param detailId 通知详情 ID
/// @param userId 用户 ID
@Override
@Transactional(TimiServerDBConfig.ROLLBACKER)
public void deleteInternalByUserId(String detailId, String userId) {
TimiException.required(detailId, "未找到通知详情 ID");
TimiException.required(userId, "未找到用户 ID");
int affected = mapper.deleteSiteByIdAndUserId(detailId, userId);
TimiException.requiredTrue(0 < affected, "未找到站内通知");
}
/// 查询用户未读站内通知数量
///
/// @param userId 用户 ID
@@ -4,10 +4,11 @@ import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
import com.imyeyu.api.modules.common.entity.Notify;
import com.imyeyu.api.modules.common.entity.NotifyDetail;
import com.imyeyu.api.modules.common.mapper.NotifyMapper;
import com.imyeyu.api.modules.common.service.NotifyService;
import com.imyeyu.api.modules.common.service.NotifyDetailService;
import com.imyeyu.api.modules.common.service.NotifyService;
import com.imyeyu.api.modules.system.entity.Logger;
import com.imyeyu.api.modules.system.service.LoggerService;
import com.imyeyu.api.modules.user.service.UserLoginService;
import com.imyeyu.java.TimiJava;
import com.imyeyu.java.bean.timi.TimiCode;
import com.imyeyu.java.bean.timi.TimiException;
@@ -31,8 +32,9 @@ import java.util.List;
@RequiredArgsConstructor
public class NotifyServiceImplement extends AbstractEntityService<Notify, String> implements NotifyService {
private final NotifyDetailService detailService;
private final LoggerService loggerService;
private final UserLoginService userLoginService;
private final NotifyDetailService detailService;
private final NotifyMapper mapper;
@@ -53,8 +55,15 @@ public class NotifyServiceImplement extends AbstractEntityService<Notify, String
TimiException.required(notify.getDetailList(), "未找到通知详情列表");
super.create(notify);
String sendFrom = null;
if (userLoginService.isLogged()) {
sendFrom = userLoginService.getRequireLoginUserId();
}
for (NotifyDetail detail : notify.getDetailList()) {
detail.setNotifyId(notify.getId());
if (TimiJava.isNotEmpty(sendFrom)) {
detail.setSendFrom(sendFrom);
}
detailService.create(detail);
}
logger.setLevel(Logger.Level.INFO);
@@ -0,0 +1,3 @@
ALTER TABLE `article`
CHANGE COLUMN `digest` `description` LONGTEXT COLLATE utf8mb4_unicode_ci COMMENT '描述',
ADD COLUMN `status` VARCHAR(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'NORMAL' COMMENT '文章状态,DART 草稿,NORMAL 正常,HIDDEN 隐藏' AFTER `likes`;