fix notify delete
This commit is contained in:
@@ -176,14 +176,14 @@ public class NotifyController {
|
||||
return detail;
|
||||
}
|
||||
|
||||
/// 删除当前用户的一条站内通知
|
||||
/// 隐藏当前用户的一条站内通知
|
||||
///
|
||||
/// @param id 通知详情 ID
|
||||
@RequireCorePermission(CorePermissionCode.NOTIFY_READ)
|
||||
@RequiredToken
|
||||
@PostMapping("/internal/delete")
|
||||
public void deleteInternal(@RequestParam String id) {
|
||||
detailService.deleteInternalByUserId(id, userLoginService.getRequireLoginUserId());
|
||||
detailService.hideInternalByUserId(id, userLoginService.getRequireLoginUserId());
|
||||
}
|
||||
|
||||
/// 查询当前用户未读通知数量
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.imyeyu.api.modules.common.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonView;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.imyeyu.api.TimiServerAPI;
|
||||
@@ -157,6 +158,10 @@ public class NotifyDetail extends UUIDEntity {
|
||||
@JsonView(ResponseView.Public.class)
|
||||
private Long readAt;
|
||||
|
||||
/// 收件人隐藏时间,仅站内通知生效
|
||||
@JsonIgnore
|
||||
private Long hiddenAt;
|
||||
|
||||
@Transient
|
||||
protected Notify notify;
|
||||
|
||||
|
||||
@@ -16,35 +16,37 @@ import java.util.List;
|
||||
*/
|
||||
public interface NotifyDetailMapper extends BaseMapper<NotifyDetail, String> {
|
||||
|
||||
String NOT_HIDDEN = " AND `hidden_at` IS NULL";
|
||||
|
||||
/** 查询用户的站内通知 */
|
||||
@Select("SELECT * FROM `notify_detail` WHERE `msg_type` = 'INTERNAL' AND `send_to` = #{userId} AND `send_at` < " + UNIX_TIME + NOT_DELETE + " ORDER BY `created_at` DESC LIMIT #{offset}, #{limit}")
|
||||
@Select("SELECT * FROM `notify_detail` WHERE `msg_type` = 'INTERNAL' AND `send_to` = #{userId} AND `send_at` < " + UNIX_TIME + NOT_HIDDEN + NOT_DELETE + " ORDER BY `created_at` DESC LIMIT #{offset}, #{limit}")
|
||||
List<NotifyDetail> selectSiteByUserId(@Param("userId") String userId, @Param("offset") long offset, @Param("limit") long limit);
|
||||
|
||||
/** 查询用户的未读站内通知 */
|
||||
@Select("SELECT * FROM `notify_detail` WHERE `msg_type` = 'INTERNAL' AND `send_to` = #{userId} AND `send_at` < " + UNIX_TIME + " AND `read_at` IS NULL " + NOT_DELETE + " ORDER BY `created_at` DESC LIMIT #{offset}, #{limit}")
|
||||
@Select("SELECT * FROM `notify_detail` WHERE `msg_type` = 'INTERNAL' AND `send_to` = #{userId} AND `send_at` < " + UNIX_TIME + " AND `read_at` IS NULL " + NOT_HIDDEN + NOT_DELETE + " ORDER BY `created_at` DESC LIMIT #{offset}, #{limit}")
|
||||
List<NotifyDetail> selectUnreadSiteByUserId(@Param("userId") String userId, @Param("offset") long offset, @Param("limit") long limit);
|
||||
|
||||
/** 统计用户的站内通知数量 */
|
||||
@Select("SELECT COUNT(*) FROM `notify_detail` WHERE `msg_type` = 'INTERNAL' AND `send_to` = #{userId} AND `send_at` < " + UNIX_TIME + NOT_DELETE)
|
||||
@Select("SELECT COUNT(*) FROM `notify_detail` WHERE `msg_type` = 'INTERNAL' AND `send_to` = #{userId} AND `send_at` < " + UNIX_TIME + NOT_HIDDEN + NOT_DELETE)
|
||||
long countSiteByUserId(@Param("userId") String userId);
|
||||
|
||||
/** 统计用户的未读站内通知数量 */
|
||||
@Select("SELECT COUNT(*) FROM `notify_detail` WHERE `msg_type` = 'INTERNAL' AND `send_to` = #{userId} AND `send_at` < " + UNIX_TIME + " AND `read_at` IS NULL " + NOT_DELETE)
|
||||
@Select("SELECT COUNT(*) FROM `notify_detail` WHERE `msg_type` = 'INTERNAL' AND `send_to` = #{userId} AND `send_at` < " + UNIX_TIME + " AND `read_at` IS NULL " + NOT_HIDDEN + NOT_DELETE)
|
||||
long countUnreadSiteByUserId(@Param("userId") String userId);
|
||||
|
||||
/** 查询用户拥有的站内通知 */
|
||||
@Select("SELECT * FROM `notify_detail` WHERE `id` = #{detailId} AND `msg_type` = 'INTERNAL' AND `send_to` = #{userId} AND `send_at` < " + UNIX_TIME + NOT_DELETE + " LIMIT 1")
|
||||
@Select("SELECT * FROM `notify_detail` WHERE `id` = #{detailId} AND `msg_type` = 'INTERNAL' AND `send_to` = #{userId} AND `send_at` < " + UNIX_TIME + NOT_HIDDEN + 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} AND `send_at` < " + UNIX_TIME + NOT_DELETE)
|
||||
int deleteSiteByIdAndUserId(@Param("detailId") String detailId, @Param("userId") String userId);
|
||||
/** 隐藏用户的站内通知 */
|
||||
@Update("UPDATE `notify_detail` SET `hidden_at` = " + UNIX_TIME + ", `updated_at` = " + UNIX_TIME + " WHERE `id` = #{detailId} AND `msg_type` = 'INTERNAL' AND `send_to` = #{userId} AND `send_at` < " + UNIX_TIME + NOT_HIDDEN + NOT_DELETE)
|
||||
int hideSiteByIdAndUserId(@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 `send_at` < " + UNIX_TIME + " AND `read_at` IS NULL " + NOT_DELETE)
|
||||
@Update("UPDATE `notify_detail` SET `read_at` = #{readAt}, `updated_at` = " + UNIX_TIME + " WHERE `id` = #{detailId} AND `msg_type` = 'INTERNAL' AND `send_to` = #{userId} AND `send_at` < " + UNIX_TIME + " AND `read_at` IS NULL " + NOT_HIDDEN + NOT_DELETE)
|
||||
int markSiteRead(@Param("detailId") String detailId, @Param("userId") String userId, @Param("readAt") long readAt);
|
||||
|
||||
/** 标记用户全部站内通知已读 */
|
||||
@Update("UPDATE `notify_detail` SET `read_at` = #{readAt}, `updated_at` = " + UNIX_TIME + " WHERE `msg_type` = 'INTERNAL' AND `send_to` = #{userId} AND `send_at` < " + UNIX_TIME + " AND `read_at` IS NULL " + NOT_DELETE)
|
||||
@Update("UPDATE `notify_detail` SET `read_at` = #{readAt}, `updated_at` = " + UNIX_TIME + " WHERE `msg_type` = 'INTERNAL' AND `send_to` = #{userId} AND `send_at` < " + UNIX_TIME + " AND `read_at` IS NULL " + NOT_HIDDEN + NOT_DELETE)
|
||||
int markAllSiteRead(@Param("userId") String userId, @Param("readAt") long readAt);
|
||||
}
|
||||
|
||||
@@ -41,11 +41,11 @@ public interface NotifyDetailService extends BaseService<NotifyDetail, String> {
|
||||
/// @return 通知详情
|
||||
NotifyDetail getInternalByUserId(String detailId, String userId);
|
||||
|
||||
/// 删除当前用户拥有的站内通知详情
|
||||
/// 隐藏当前用户拥有的站内通知详情
|
||||
///
|
||||
/// @param detailId 通知详情 ID
|
||||
/// @param userId 用户 ID
|
||||
void deleteInternalByUserId(String detailId, String userId);
|
||||
void hideInternalByUserId(String detailId, String userId);
|
||||
|
||||
/// 查询用户未读站内通知数量
|
||||
///
|
||||
|
||||
+3
-3
@@ -202,16 +202,16 @@ public class NotifyDetailServiceImplement extends AbstractEntityService<NotifyDe
|
||||
}
|
||||
}
|
||||
|
||||
/// 删除当前用户拥有的站内通知详情
|
||||
/// 隐藏当前用户拥有的站内通知详情
|
||||
///
|
||||
/// @param detailId 通知详情 ID
|
||||
/// @param userId 用户 ID
|
||||
@Override
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
public void deleteInternalByUserId(String detailId, String userId) {
|
||||
public void hideInternalByUserId(String detailId, String userId) {
|
||||
TimiException.required(detailId, "未找到通知详情 ID");
|
||||
TimiException.required(userId, "未找到用户 ID");
|
||||
int affected = mapper.deleteSiteByIdAndUserId(detailId, userId);
|
||||
int affected = mapper.hideSiteByIdAndUserId(detailId, userId);
|
||||
TimiException.requiredTrue(0 < affected, "未找到站内通知");
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,10 @@ import com.fasterxml.jackson.annotation.JsonView;
|
||||
import com.imyeyu.api.annotation.RequireCorePermission;
|
||||
import com.imyeyu.api.bean.CorePermissionCode;
|
||||
import com.imyeyu.api.bean.PermissionMatchMode;
|
||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||
import com.imyeyu.api.modules.common.entity.Notify;
|
||||
import com.imyeyu.api.modules.common.entity.NotifyDetail;
|
||||
import com.imyeyu.api.modules.common.service.AttachmentService;
|
||||
import com.imyeyu.api.modules.common.service.NotifyService;
|
||||
import com.imyeyu.api.modules.gao.annotation.RequireGaoPermission;
|
||||
import com.imyeyu.api.modules.gao.bean.GaoPermissionCode;
|
||||
@@ -13,6 +15,7 @@ import com.imyeyu.api.modules.gao.entity.GaoUser;
|
||||
import com.imyeyu.api.modules.gao.service.GaoStoreScopeService;
|
||||
import com.imyeyu.api.modules.gao.service.GaoUserService;
|
||||
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.java.bean.timi.TimiException;
|
||||
@@ -35,7 +38,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
/// GAO 通知接口
|
||||
///
|
||||
/// 这里的通知接收用户必须属于当前操作人的 GAO 用户范围,不能直接复用通用通知创建接口。
|
||||
/// 这里的通知接收用户必须属于当前操作人的 GAO 用户范围,当前登录用户本人除外。
|
||||
///
|
||||
/// @author Codex
|
||||
/// @since 2026-08-25
|
||||
@@ -47,7 +50,9 @@ public class GaoNotifyController {
|
||||
private final GaoUserService gaoUserService;
|
||||
private final GaoStoreScopeService storeScopeService;
|
||||
private final NotifyService notifyService;
|
||||
private final UserLoginService userLoginService;
|
||||
private final UserService userService;
|
||||
private final AttachmentService attachmentService;
|
||||
|
||||
/// 查询可作为通知接收人的 GAO 用户
|
||||
///
|
||||
@@ -64,7 +69,6 @@ public class GaoNotifyController {
|
||||
public PageResult<GaoUser> recipientList(@RequestBody Page<GaoUser> page) {
|
||||
TimiException.required(page, "未找到分页参数");
|
||||
GaoUser example = TimiJava.defaultIfNull(page.getEqualsExample(), new GaoUser());
|
||||
example.setEnabled(true);
|
||||
if (storeScopeService.hasGlobalScope()) {
|
||||
if (TimiJava.isNotEmpty(example.getStoreId())) {
|
||||
storeScopeService.checkStoreId(example.getStoreId());
|
||||
@@ -74,14 +78,14 @@ public class GaoNotifyController {
|
||||
}
|
||||
page.setEqualsExample(example);
|
||||
|
||||
PageResult<GaoUser> result = gaoUserService.page(page);
|
||||
PageResult<GaoUser> result = gaoUserService.pageRecipients(page);
|
||||
fillUser(result.getList());
|
||||
return result;
|
||||
}
|
||||
|
||||
/// 创建 GAO 站内通知
|
||||
///
|
||||
/// 只允许发送站内通知,并逐个校验接收用户是否属于当前操作人的门店范围。
|
||||
/// 只允许发送站内通知,并逐个校验接收用户是否属于当前操作人的门店范围;当前用户可以接收自己发送的通知。
|
||||
///
|
||||
/// @param notify 通知及通知详情
|
||||
/// @return 创建后的通知
|
||||
@@ -116,8 +120,12 @@ public class GaoNotifyController {
|
||||
}).collect(Collectors.toSet());
|
||||
TimiException.requiredTrue(recipientIdSet.size() == detailList.size(), "通知接收用户不能重复");
|
||||
|
||||
Map<String, GaoUser> gaoUserMap = gaoUserService.mapByUserIdList(recipientIdSet);
|
||||
TimiException.requiredTrue(gaoUserMap.size() == recipientIdSet.size(), "包含无效的通知接收用户");
|
||||
String loginUserId = userLoginService.getRequireLoginUserId();
|
||||
Set<String> gaoRecipientIdSet = recipientIdSet.stream()
|
||||
.filter(recipientId -> !loginUserId.equals(recipientId))
|
||||
.collect(Collectors.toSet());
|
||||
Map<String, GaoUser> gaoUserMap = gaoUserService.mapByUserIdList(gaoRecipientIdSet);
|
||||
TimiException.requiredTrue(gaoUserMap.size() == gaoRecipientIdSet.size(), "包含无效的通知接收用户");
|
||||
for (GaoUser gaoUser : gaoUserMap.values()) {
|
||||
TimiException.requiredTrue(Boolean.TRUE.equals(gaoUser.getEnabled()), "通知接收用户已停用");
|
||||
storeScopeService.checkStoreId(gaoUser.getStoreId());
|
||||
@@ -133,8 +141,18 @@ public class GaoNotifyController {
|
||||
}
|
||||
List<String> userIdList = gaoUserList.stream().map(GaoUser::getUserId).toList();
|
||||
Map<String, User> userMap = userService.mapByIdList(userIdList);
|
||||
Map<String, List<Attachment>> attachmentMap = attachmentService.mapByBizIdList(
|
||||
Attachment.BizType.USER,
|
||||
userIdList,
|
||||
User.AttachType.AVATAR.toString()
|
||||
);
|
||||
for (GaoUser gaoUser : gaoUserList) {
|
||||
gaoUser.setUser(userMap.get(gaoUser.getUserId()));
|
||||
User user = userMap.get(gaoUser.getUserId());
|
||||
if (user == null) {
|
||||
continue;
|
||||
}
|
||||
user.setAttachmentList(attachmentMap.getOrDefault(user.getId(), List.of()));
|
||||
gaoUser.setUser(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package com.imyeyu.api.modules.gao.mapper;
|
||||
|
||||
import com.imyeyu.api.modules.gao.entity.GaoUser;
|
||||
import com.imyeyu.spring.bean.Page;
|
||||
import com.imyeyu.spring.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -14,4 +16,8 @@ import java.util.List;
|
||||
public interface GaoUserMapper extends BaseMapper<GaoUser, String> {
|
||||
|
||||
List<GaoUser> selectByUserIdList(Collection<String> userIdList);
|
||||
|
||||
List<GaoUser> selectRecipientPage(@Param("page") Page<GaoUser> page);
|
||||
|
||||
long countRecipients(@Param("page") Page<GaoUser> page);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.imyeyu.api.modules.gao.service;
|
||||
|
||||
import com.imyeyu.api.modules.gao.entity.GaoUser;
|
||||
import com.imyeyu.spring.bean.Page;
|
||||
import com.imyeyu.spring.bean.PageResult;
|
||||
import com.imyeyu.spring.service.BaseService;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -28,4 +30,10 @@ public interface GaoUserService extends BaseService<GaoUser, String> {
|
||||
/// @param userIdList 核心用户 ID 列表
|
||||
/// @return GAO 用户映射
|
||||
Map<String, GaoUser> mapByUserIdList(Collection<String> userIdList);
|
||||
|
||||
/// 查询可作为通知接收人的启用用户
|
||||
///
|
||||
/// @param page 分页参数
|
||||
/// @return 接收用户分页结果
|
||||
PageResult<GaoUser> pageRecipients(Page<GaoUser> page);
|
||||
}
|
||||
|
||||
+10
@@ -13,6 +13,8 @@ import com.imyeyu.java.TimiJava;
|
||||
import com.imyeyu.java.bean.timi.TimiCode;
|
||||
import com.imyeyu.java.bean.timi.TimiException;
|
||||
import com.imyeyu.spring.mapper.BaseMapper;
|
||||
import com.imyeyu.spring.bean.Page;
|
||||
import com.imyeyu.spring.bean.PageResult;
|
||||
import com.imyeyu.spring.service.AbstractEntityService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -174,4 +176,12 @@ public class GaoUserServiceImplement extends AbstractEntityService<GaoUser, Stri
|
||||
return mapper.selectByUserIdList(userIdList).stream()
|
||||
.collect(Collectors.toMap(GaoUser::getUserId, Function.identity()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<GaoUser> pageRecipients(Page<GaoUser> page) {
|
||||
PageResult<GaoUser> result = new PageResult<>();
|
||||
result.setTotal(mapper.countRecipients(page));
|
||||
result.setList(mapper.selectRecipientPage(page));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
ALTER TABLE `notify_detail`
|
||||
ADD COLUMN `hidden_at` BIGINT(20) COMMENT '收件人隐藏时间' AFTER `read_at`,
|
||||
DROP INDEX `idx_internal_user_send_at`,
|
||||
ADD INDEX `idx_internal_user_send_at`(`msg_type` ASC, `send_to` ASC, `hidden_at` ASC, `send_at` ASC, `deleted_at` ASC) USING BTREE;
|
||||
@@ -12,4 +12,26 @@
|
||||
</foreach>
|
||||
AND `deleted_at` IS NULL
|
||||
</select>
|
||||
|
||||
<select id="selectRecipientPage" resultType="com.imyeyu.api.modules.gao.entity.GaoUser">
|
||||
SELECT *
|
||||
FROM `gao_user`
|
||||
WHERE `enabled` = 1
|
||||
AND (`deleted_at` IS NULL OR FLOOR(UNIX_TIMESTAMP(NOW(3)) * 1000) < `deleted_at`)
|
||||
<if test="page.equalsExample != null and page.equalsExample.storeId != null and page.equalsExample.storeId != ''">
|
||||
AND `store_id` = #{page.equalsExample.storeId}
|
||||
</if>
|
||||
ORDER BY COALESCE(`updated_at`, `created_at`) DESC
|
||||
LIMIT #{page.offset}, #{page.limit}
|
||||
</select>
|
||||
|
||||
<select id="countRecipients" resultType="long">
|
||||
SELECT COUNT(*)
|
||||
FROM `gao_user`
|
||||
WHERE `enabled` = 1
|
||||
AND (`deleted_at` IS NULL OR FLOOR(UNIX_TIMESTAMP(NOW(3)) * 1000) < `deleted_at`)
|
||||
<if test="page.equalsExample != null and page.equalsExample.storeId != null and page.equalsExample.storeId != ''">
|
||||
AND `store_id` = #{page.equalsExample.storeId}
|
||||
</if>
|
||||
</select>
|
||||
</mapper>
|
||||
|
||||
Reference in New Issue
Block a user