feat(asset): 添加借用到期归还提醒功能

- 新增AmsBorrowOrderMapper查询到期借用单据接口
- 实现BorrowReturnReminderService借用到期提醒服务
- 添加SysNoticeReceiver通知接收人相关实体和接口
- 集成系统通知公告模块支持定向消息推送
- 完善通知查看权限控制和防重复提醒机制
- 编写单元测试验证提醒逻辑和数据完整性
main
yangk 5 days ago
parent b45c3ab2bd
commit 1c029399c7

@ -14,11 +14,13 @@ import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.ShiroUtils;
import com.ruoyi.system.domain.SysNotice;
import com.ruoyi.system.service.ISysNoticeReceiverService;
import com.ruoyi.system.service.ISysNoticeReadService;
import com.ruoyi.system.service.ISysNoticeService;
@ -39,6 +41,9 @@ public class SysNoticeController extends BaseController
@Autowired
private ISysNoticeReadService noticeReadService;
@Autowired
private ISysNoticeReceiverService noticeReceiverService;
@RequiresPermissions("system:notice:view")
@GetMapping()
public String notice()
@ -112,7 +117,14 @@ public class SysNoticeController extends BaseController
@GetMapping("/view/{noticeId}")
public String view(@PathVariable("noticeId") Long noticeId, ModelMap mmap)
{
mmap.put("notice", noticeService.selectNoticeById(noticeId));
SysNotice notice = noticeService.selectNoticeById(noticeId);
SysUser currentUser = ShiroUtils.getSysUser();
Long userId = currentUser == null ? null : currentUser.getUserId();
if (notice == null || (!noticeReceiverService.canViewNotice(noticeId, userId) && !canManageNotice(userId)))
{
return "error/unauth";
}
mmap.put("notice", notice);
return prefix + "/view";
}
@ -189,7 +201,13 @@ public class SysNoticeController extends BaseController
@ResponseBody
public AjaxResult remove(String ids)
{
noticeReceiverService.deleteByNoticeIds(ids);
noticeReadService.deleteByNoticeIds(ids);
return toAjax(noticeService.deleteNoticeByIds(ids));
}
private boolean canManageNotice(Long userId)
{
return ShiroUtils.isAdmin(userId) || ShiroUtils.getSubject().isPermitted("system:notice:list");
}
}

@ -39,6 +39,16 @@ public interface AmsBorrowOrderMapper
*/
public List<AmsBorrowOrder> selectAmsBorrowOrderList(AmsBorrowOrder amsBorrowOrder);
/**
*
*
* @param orderStatus
* @param detailStatus
* @return
*/
public List<AmsBorrowOrder> selectOverdueBorrowReturnReminderCandidates(@Param("orderStatus") String orderStatus,
@Param("detailStatus") String detailStatus);
/**
*
*

@ -0,0 +1,16 @@
package com.ruoyi.asset.service;
/**
*
*
* @author Yangk
*/
public interface IBorrowReturnReminderService
{
/**
*
*
* @return
*/
public int remindOverdueBorrowOrders();
}

@ -0,0 +1,134 @@
package com.ruoyi.asset.service.impl;
import java.text.SimpleDateFormat;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.util.HtmlUtils;
import com.ruoyi.asset.constant.BorrowOrderStatus;
import com.ruoyi.asset.domain.AmsBorrowOrder;
import com.ruoyi.asset.mapper.AmsBorrowOrderMapper;
import com.ruoyi.asset.service.IBorrowReturnReminderService;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.system.domain.SysNotice;
import com.ruoyi.system.domain.SysNoticeReceiver;
import com.ruoyi.system.service.ISysNoticeReceiverService;
import com.ruoyi.system.service.ISysNoticeService;
/**
*
*
* @author Yangk
*/
@Service("borrowReturnReminderService")
public class BorrowReturnReminderServiceImpl implements IBorrowReturnReminderService
{
private static final String SOURCE_TYPE_BORROW_OVERDUE = "BORROW_OVERDUE";
private static final int NOTICE_TITLE_MAX_LENGTH = 50;
private static final String NOTICE_TYPE_NOTICE = "1";
private static final String NOTICE_STATUS_NORMAL = "0";
private static final String SYSTEM_USER = "system";
@Autowired
private AmsBorrowOrderMapper amsBorrowOrderMapper;
@Autowired
private ISysNoticeService noticeService;
@Autowired
private ISysNoticeReceiverService noticeReceiverService;
@Override
@Transactional(rollbackFor = Exception.class)
public int remindOverdueBorrowOrders()
{
List<AmsBorrowOrder> candidates = amsBorrowOrderMapper.selectOverdueBorrowReturnReminderCandidates(
BorrowOrderStatus.BORROWING, BorrowOrderStatus.BORROWING);
int createdCount = 0;
for (AmsBorrowOrder order : candidates)
{
if (order.getOrderId() == null || order.getBorrowUserId() == null)
{
continue;
}
if (noticeReceiverService.isSourceNotified(SOURCE_TYPE_BORROW_OVERDUE, order.getOrderId(),
order.getBorrowUserId()))
{
continue;
}
createdCount += createReminder(order);
}
return createdCount;
}
private int createReminder(AmsBorrowOrder order)
{
SysNotice notice = new SysNotice();
notice.setNoticeTitle(truncate("借用资产到期归还提醒:" + defaultString(order.getBorrowNo()),
NOTICE_TITLE_MAX_LENGTH));
notice.setNoticeType(NOTICE_TYPE_NOTICE);
notice.setStatus(NOTICE_STATUS_NORMAL);
notice.setCreateBy(SYSTEM_USER);
notice.setNoticeContent(buildNoticeContent(order));
if (noticeService.insertNotice(notice) != 1 || notice.getNoticeId() == null)
{
throw new ServiceException("借用到期提醒生成失败,通知公告写入异常");
}
SysNoticeReceiver receiver = new SysNoticeReceiver();
receiver.setNoticeId(notice.getNoticeId());
receiver.setUserId(order.getBorrowUserId());
receiver.setSourceType(SOURCE_TYPE_BORROW_OVERDUE);
receiver.setSourceId(order.getOrderId());
// 业务来源唯一键兜底防重,避免每天定时任务重复提醒同一借用单。
if (noticeReceiverService.insertNoticeReceiver(receiver) != 1)
{
throw new ServiceException("借用到期提醒生成失败,接收人写入异常");
}
return 1;
}
private String buildNoticeContent(AmsBorrowOrder order)
{
String borrowNo = escape(order.getBorrowNo());
String borrowUserName = escape(order.getBorrowUserName());
String expectedReturnDate = formatDate(order);
return "<p>借用单号:" + borrowNo + "</p>"
+ "<p>借用人:" + borrowUserName + "</p>"
+ "<p>预计归还日期:" + expectedReturnDate + "</p>"
+ "<p>该借用单已到预计归还日期,请及时发起归还申请或联系管理员处理。</p>";
}
private String formatDate(AmsBorrowOrder order)
{
if (order.getExpectedReturnDate() == null)
{
return "";
}
return new SimpleDateFormat("yyyy-MM-dd").format(order.getExpectedReturnDate());
}
private String escape(String value)
{
return HtmlUtils.htmlEscape(defaultString(value));
}
private String defaultString(String value)
{
return value == null ? "" : value;
}
private String truncate(String value, int maxLength)
{
if (value == null || value.length() <= maxLength)
{
return value;
}
return value.substring(0, maxLength);
}
}

@ -118,6 +118,23 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
where order_id = #{orderId} and del_flag = '0'
</select>
<select id="selectOverdueBorrowReturnReminderCandidates" resultMap="AmsBorrowOrderResult">
<include refid="selectAmsBorrowOrderVo"/>
where del_flag = '0'
and order_status = #{orderStatus}
and expected_return_date is not null
and expected_return_date &lt;= curdate()
and borrow_user_id is not null
and exists (
select 1
from ams_borrow_order_item item
where item.order_id = ams_borrow_order.order_id
and item.del_flag = '0'
and item.return_status = #{detailStatus}
)
order by expected_return_date asc, order_id asc
</select>
<select id="selectAmsBorrowOrderByOrderIdForUpdate" parameterType="Long" resultMap="AmsBorrowOrderAmsBorrowOrderItemResult">
<include refid="selectAmsBorrowOrderVo"/>
where order_id = #{orderId} and del_flag = '0'

@ -0,0 +1,126 @@
package com.ruoyi.asset.service.impl;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Collections;
import java.util.Date;
import com.ruoyi.asset.constant.BorrowOrderStatus;
import com.ruoyi.asset.domain.AmsBorrowOrder;
import com.ruoyi.asset.mapper.AmsBorrowOrderMapper;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.system.domain.SysNotice;
import com.ruoyi.system.domain.SysNoticeReceiver;
import com.ruoyi.system.service.ISysNoticeReceiverService;
import com.ruoyi.system.service.ISysNoticeService;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
class BorrowReturnReminderServiceImplTest
{
@Mock
private AmsBorrowOrderMapper amsBorrowOrderMapper;
@Mock
private ISysNoticeService noticeService;
@Mock
private ISysNoticeReceiverService noticeReceiverService;
@InjectMocks
private BorrowReturnReminderServiceImpl service;
/** 到期借用单只给借用人生成一条定向提醒。 */
@Test
void remindShouldCreateDirectedNoticeForDueCandidate()
{
AmsBorrowOrder order = buildOrder();
when(amsBorrowOrderMapper.selectOverdueBorrowReturnReminderCandidates(
BorrowOrderStatus.BORROWING, BorrowOrderStatus.BORROWING))
.thenReturn(Collections.singletonList(order));
when(noticeReceiverService.isSourceNotified("BORROW_OVERDUE", 100L, 2L)).thenReturn(false);
doAnswer(invocation -> {
SysNotice notice = invocation.getArgument(0);
notice.setNoticeId(900L);
return 1;
}).when(noticeService).insertNotice(any(SysNotice.class));
when(noticeReceiverService.insertNoticeReceiver(any(SysNoticeReceiver.class))).thenReturn(1);
assertEquals(1, service.remindOverdueBorrowOrders());
ArgumentCaptor<SysNotice> noticeCaptor = ArgumentCaptor.forClass(SysNotice.class);
verify(noticeService).insertNotice(noticeCaptor.capture());
assertEquals("借用资产到期归还提醒JY202607060001", noticeCaptor.getValue().getNoticeTitle());
assertEquals("1", noticeCaptor.getValue().getNoticeType());
assertEquals("0", noticeCaptor.getValue().getStatus());
assertTrue(noticeCaptor.getValue().getNoticeContent().contains("JY202607060001"));
assertTrue(noticeCaptor.getValue().getNoticeContent().contains("张三"));
ArgumentCaptor<SysNoticeReceiver> receiverCaptor = ArgumentCaptor.forClass(SysNoticeReceiver.class);
verify(noticeReceiverService).insertNoticeReceiver(receiverCaptor.capture());
assertEquals(900L, receiverCaptor.getValue().getNoticeId());
assertEquals(2L, receiverCaptor.getValue().getUserId());
assertEquals("BORROW_OVERDUE", receiverCaptor.getValue().getSourceType());
assertEquals(100L, receiverCaptor.getValue().getSourceId());
}
/** 已存在业务来源提醒时直接跳过,避免重复刷屏。 */
@Test
void remindShouldSkipAlreadyNotifiedOrder()
{
AmsBorrowOrder order = buildOrder();
when(amsBorrowOrderMapper.selectOverdueBorrowReturnReminderCandidates(
BorrowOrderStatus.BORROWING, BorrowOrderStatus.BORROWING))
.thenReturn(Collections.singletonList(order));
when(noticeReceiverService.isSourceNotified("BORROW_OVERDUE", 100L, 2L)).thenReturn(true);
assertEquals(0, service.remindOverdueBorrowOrders());
verify(noticeService, never()).insertNotice(any(SysNotice.class));
verify(noticeReceiverService, never()).insertNoticeReceiver(any(SysNoticeReceiver.class));
}
/** 接收人写入失败时回滚整个提醒事务,避免留下无接收人的孤立通知。 */
@Test
void remindShouldFailFastWhenReceiverInsertFails()
{
AmsBorrowOrder order = buildOrder();
when(amsBorrowOrderMapper.selectOverdueBorrowReturnReminderCandidates(
BorrowOrderStatus.BORROWING, BorrowOrderStatus.BORROWING))
.thenReturn(Collections.singletonList(order));
when(noticeReceiverService.isSourceNotified("BORROW_OVERDUE", 100L, 2L)).thenReturn(false);
doAnswer(invocation -> {
SysNotice notice = invocation.getArgument(0);
notice.setNoticeId(900L);
return 1;
}).when(noticeService).insertNotice(any(SysNotice.class));
when(noticeReceiverService.insertNoticeReceiver(any(SysNoticeReceiver.class))).thenReturn(0);
ServiceException exception = assertThrows(ServiceException.class,
() -> service.remindOverdueBorrowOrders());
assertTrue(exception.getMessage().contains("接收人写入异常"));
}
private AmsBorrowOrder buildOrder()
{
AmsBorrowOrder order = new AmsBorrowOrder();
order.setOrderId(100L);
order.setBorrowNo("JY202607060001");
order.setBorrowUserId(2L);
order.setBorrowUserName("张三");
order.setExpectedReturnDate(new Date(1783267200000L));
return order;
}
}

@ -0,0 +1,75 @@
package com.ruoyi.asset.service.impl;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.ruoyi.system.domain.SysNoticeReceiver;
import com.ruoyi.system.mapper.SysNoticeReceiverMapper;
import com.ruoyi.system.service.impl.SysNoticeReceiverServiceImpl;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
class SysNoticeReceiverServiceImplTest
{
@Mock
private SysNoticeReceiverMapper noticeReceiverMapper;
@InjectMocks
private SysNoticeReceiverServiceImpl service;
/** 没有接收人记录的通知仍是全员公告。 */
@Test
void canViewNoticeShouldAllowGlobalNotice()
{
when(noticeReceiverMapper.countReceiverByNoticeId(10L)).thenReturn(0);
assertTrue(service.canViewNotice(10L, 2L));
}
/** 存在接收人记录时,只有命中的用户可见。 */
@Test
void canViewNoticeShouldAllowOnlyMatchedReceiver()
{
when(noticeReceiverMapper.countReceiverByNoticeId(10L)).thenReturn(1);
when(noticeReceiverMapper.countReceiverByNoticeIdAndUserId(10L, 2L)).thenReturn(1);
when(noticeReceiverMapper.countReceiverByNoticeIdAndUserId(10L, 3L)).thenReturn(0);
assertTrue(service.canViewNotice(10L, 2L));
assertFalse(service.canViewNotice(10L, 3L));
}
/** 业务来源唯一键用于判断同一借用单是否已经提醒过该借用人。 */
@Test
void isSourceNotifiedShouldUseSourceAndUser()
{
when(noticeReceiverMapper.countBySource("BORROW_OVERDUE", 100L, 2L)).thenReturn(1);
assertTrue(service.isSourceNotified("BORROW_OVERDUE", 100L, 2L));
assertFalse(service.isSourceNotified(null, 100L, 2L));
}
/** 接收人创建时间由服务层兜底,避免调用方漏填导致审计字段为空。 */
@Test
void insertNoticeReceiverShouldFillCreateTime()
{
SysNoticeReceiver receiver = new SysNoticeReceiver();
receiver.setNoticeId(10L);
receiver.setUserId(2L);
receiver.setSourceType("BORROW_OVERDUE");
receiver.setSourceId(100L);
service.insertNoticeReceiver(receiver);
ArgumentCaptor<SysNoticeReceiver> receiverCaptor = ArgumentCaptor.forClass(SysNoticeReceiver.class);
verify(noticeReceiverMapper).insertNoticeReceiver(receiverCaptor.capture());
assertNotNull(receiverCaptor.getValue().getCreateTime());
}
}

@ -0,0 +1,109 @@
package com.ruoyi.system.domain;
import java.util.Date;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.ruoyi.common.core.domain.BaseEntity;
/**
* sys_notice_receiver
*
* @author ruoyi
*/
public class SysNoticeReceiver extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** 接收人主键 */
private Long receiverId;
/** 通知公告ID */
private Long noticeId;
/** 接收用户ID */
private Long userId;
/** 业务来源类型 */
private String sourceType;
/** 业务来源ID */
private Long sourceId;
/** 创建时间 */
private Date createTime;
public Long getReceiverId()
{
return receiverId;
}
public void setReceiverId(Long receiverId)
{
this.receiverId = receiverId;
}
public Long getNoticeId()
{
return noticeId;
}
public void setNoticeId(Long noticeId)
{
this.noticeId = noticeId;
}
public Long getUserId()
{
return userId;
}
public void setUserId(Long userId)
{
this.userId = userId;
}
public String getSourceType()
{
return sourceType;
}
public void setSourceType(String sourceType)
{
this.sourceType = sourceType;
}
public Long getSourceId()
{
return sourceId;
}
public void setSourceId(Long sourceId)
{
this.sourceId = sourceId;
}
@Override
public Date getCreateTime()
{
return createTime;
}
@Override
public void setCreateTime(Date createTime)
{
this.createTime = createTime;
}
@Override
public String toString()
{
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
.append("receiverId", getReceiverId())
.append("noticeId", getNoticeId())
.append("userId", getUserId())
.append("sourceType", getSourceType())
.append("sourceId", getSourceId())
.append("createTime", getCreateTime())
.toString();
}
}

@ -0,0 +1,56 @@
package com.ruoyi.system.mapper;
import org.apache.ibatis.annotations.Param;
import com.ruoyi.system.domain.SysNoticeReceiver;
/**
*
*
* @author ruoyi
*/
public interface SysNoticeReceiverMapper
{
/**
*
*
* @param noticeReceiver
* @return
*/
public int insertNoticeReceiver(SysNoticeReceiver noticeReceiver);
/**
*
*
* @param noticeId ID
* @return
*/
public int countReceiverByNoticeId(@Param("noticeId") Long noticeId);
/**
*
*
* @param noticeId ID
* @param userId ID
* @return
*/
public int countReceiverByNoticeIdAndUserId(@Param("noticeId") Long noticeId, @Param("userId") Long userId);
/**
*
*
* @param sourceType
* @param sourceId ID
* @param userId ID
* @return
*/
public int countBySource(@Param("sourceType") String sourceType, @Param("sourceId") Long sourceId,
@Param("userId") Long userId);
/**
*
*
* @param noticeIds ID
* @return
*/
public int deleteByNoticeIds(@Param("noticeIds") String[] noticeIds);
}

@ -0,0 +1,45 @@
package com.ruoyi.system.service;
import com.ruoyi.system.domain.SysNoticeReceiver;
/**
*
*
* @author ruoyi
*/
public interface ISysNoticeReceiverService
{
/**
*
*
* @param noticeId ID
* @param userId ID
* @return true
*/
public boolean canViewNotice(Long noticeId, Long userId);
/**
*
*
* @param sourceType
* @param sourceId ID
* @param userId ID
* @return true
*/
public boolean isSourceNotified(String sourceType, Long sourceId, Long userId);
/**
*
*
* @param noticeReceiver
* @return
*/
public int insertNoticeReceiver(SysNoticeReceiver noticeReceiver);
/**
*
*
* @param ids ID
*/
public void deleteByNoticeIds(String ids);
}

@ -2,12 +2,14 @@ package com.ruoyi.system.service.impl;
import java.util.List;
import java.util.Map;
import java.util.Arrays;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.system.domain.SysNotice;
import com.ruoyi.system.domain.SysNoticeRead;
import com.ruoyi.system.mapper.SysNoticeReadMapper;
import com.ruoyi.system.service.ISysNoticeReceiverService;
import com.ruoyi.system.service.ISysNoticeReadService;
/**
@ -21,12 +23,19 @@ public class SysNoticeReadServiceImpl implements ISysNoticeReadService
@Autowired
private SysNoticeReadMapper noticeReadMapper;
@Autowired
private ISysNoticeReceiverService noticeReceiverService;
/**
*
*/
@Override
public void markRead(Long noticeId, Long userId)
{
if (!noticeReceiverService.canViewNotice(noticeId, userId))
{
return;
}
SysNoticeRead record = new SysNoticeRead();
record.setNoticeId(noticeId);
record.setUserId(userId);
@ -61,7 +70,14 @@ public class SysNoticeReadServiceImpl implements ISysNoticeReadService
{
return;
}
noticeReadMapper.insertNoticeReadBatch(userId, noticeIds);
Long[] readableNoticeIds = Arrays.stream(noticeIds)
.filter(noticeId -> noticeReceiverService.canViewNotice(noticeId, userId))
.toArray(Long[]::new);
if (readableNoticeIds.length == 0)
{
return;
}
noticeReadMapper.insertNoticeReadBatch(userId, readableNoticeIds);
}
/**

@ -0,0 +1,66 @@
package com.ruoyi.system.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.system.domain.SysNoticeReceiver;
import com.ruoyi.system.mapper.SysNoticeReceiverMapper;
import com.ruoyi.system.service.ISysNoticeReceiverService;
/**
*
*
* @author ruoyi
*/
@Service
public class SysNoticeReceiverServiceImpl implements ISysNoticeReceiverService
{
@Autowired
private SysNoticeReceiverMapper noticeReceiverMapper;
@Override
public boolean canViewNotice(Long noticeId, Long userId)
{
if (noticeId == null || userId == null)
{
return false;
}
if (noticeReceiverMapper.countReceiverByNoticeId(noticeId) == 0)
{
return true;
}
return noticeReceiverMapper.countReceiverByNoticeIdAndUserId(noticeId, userId) > 0;
}
@Override
public boolean isSourceNotified(String sourceType, Long sourceId, Long userId)
{
if (sourceType == null || sourceId == null || userId == null)
{
return false;
}
return noticeReceiverMapper.countBySource(sourceType, sourceId, userId) > 0;
}
@Override
public int insertNoticeReceiver(SysNoticeReceiver noticeReceiver)
{
if (noticeReceiver.getCreateTime() == null)
{
noticeReceiver.setCreateTime(DateUtils.getNowDate());
}
return noticeReceiverMapper.insertNoticeReceiver(noticeReceiver);
}
@Override
public void deleteByNoticeIds(String ids)
{
String[] noticeIds = Convert.toStrArray(ids);
if (noticeIds.length == 0)
{
return;
}
noticeReceiverMapper.deleteByNoticeIds(noticeIds);
}
}

@ -43,7 +43,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
order by notice_id desc
</select>
<insert id="insertNotice" parameterType="SysNotice">
<insert id="insertNotice" parameterType="SysNotice" useGeneratedKeys="true" keyProperty="noticeId">
insert into sys_notice (
<if test="noticeTitle != null and noticeTitle != '' ">notice_title, </if>
<if test="noticeType != null and noticeType != '' ">notice_type, </if>
@ -83,4 +83,4 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</foreach>
</delete>
</mapper>
</mapper>

@ -20,7 +20,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<!-- 查询未读数量:正常状态公告 减去 当前用户已读数 -->
<select id="selectUnreadCount" resultType="int">
select count(*) from sys_notice n
where n.status = '0' and not exists (select 1 from sys_notice_read r where r.notice_id = n.notice_id and r.user_id = #{userId})
where n.status = '0'
and (
not exists (select 1 from sys_notice_receiver nr_all where nr_all.notice_id = n.notice_id)
or exists (select 1 from sys_notice_receiver nr_user where nr_user.notice_id = n.notice_id and nr_user.user_id = #{userId})
)
and not exists (select 1 from sys_notice_read r where r.notice_id = n.notice_id and r.user_id = #{userId})
</select>
<!-- 查询是否已读 -->
@ -42,6 +47,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
left join sys_notice_read r
on r.notice_id = n.notice_id and r.user_id = #{userId}
where n.status = '0'
and (
not exists (select 1 from sys_notice_receiver nr_all where nr_all.notice_id = n.notice_id)
or exists (select 1 from sys_notice_receiver nr_user where nr_user.notice_id = n.notice_id and nr_user.user_id = #{userId})
)
order by n.notice_id desc
limit #{limit}
</select>

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.system.mapper.SysNoticeReceiverMapper">
<resultMap type="SysNoticeReceiver" id="SysNoticeReceiverResult">
<id property="receiverId" column="receiver_id" />
<result property="noticeId" column="notice_id" />
<result property="userId" column="user_id" />
<result property="sourceType" column="source_type" />
<result property="sourceId" column="source_id" />
<result property="createTime" column="create_time" />
</resultMap>
<insert id="insertNoticeReceiver" parameterType="SysNoticeReceiver" useGeneratedKeys="true" keyProperty="receiverId">
insert into sys_notice_receiver (notice_id, user_id, source_type, source_id, create_time)
values (#{noticeId}, #{userId}, #{sourceType}, #{sourceId}, #{createTime})
</insert>
<select id="countReceiverByNoticeId" resultType="int">
select count(1)
from sys_notice_receiver
where notice_id = #{noticeId}
</select>
<select id="countReceiverByNoticeIdAndUserId" resultType="int">
select count(1)
from sys_notice_receiver
where notice_id = #{noticeId}
and user_id = #{userId}
</select>
<select id="countBySource" resultType="int">
select count(1)
from sys_notice_receiver
where source_type = #{sourceType}
and source_id = #{sourceId}
and user_id = #{userId}
</select>
<delete id="deleteByNoticeIds">
delete from sys_notice_receiver where notice_id in
<foreach collection="noticeIds" item="noticeId" open="(" separator="," close=")">
#{noticeId}
</foreach>
</delete>
</mapper>
Loading…
Cancel
Save