[add] 消息通知
This commit is contained in:
		@ -0,0 +1,95 @@
 | 
			
		||||
package org.dromara.message.controller;
 | 
			
		||||
 | 
			
		||||
import cn.dev33.satoken.annotation.SaCheckPermission;
 | 
			
		||||
import jakarta.annotation.Resource;
 | 
			
		||||
import jakarta.validation.constraints.NotEmpty;
 | 
			
		||||
import jakarta.validation.constraints.NotNull;
 | 
			
		||||
import org.dromara.common.core.domain.R;
 | 
			
		||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
 | 
			
		||||
import org.dromara.common.log.annotation.Log;
 | 
			
		||||
import org.dromara.common.log.enums.BusinessType;
 | 
			
		||||
import org.dromara.common.mybatis.core.page.PageQuery;
 | 
			
		||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
 | 
			
		||||
import org.dromara.common.satoken.utils.LoginHelper;
 | 
			
		||||
import org.dromara.common.web.core.BaseController;
 | 
			
		||||
import org.dromara.message.domain.dto.notification.MsgNotificationQueryReq;
 | 
			
		||||
import org.dromara.message.domain.dto.notification.MsgNotificationSendMessageReq;
 | 
			
		||||
import org.dromara.message.domain.vo.notification.MsgNotificationVo;
 | 
			
		||||
import org.dromara.message.service.IMsgNotificationService;
 | 
			
		||||
import org.springframework.validation.annotation.Validated;
 | 
			
		||||
import org.springframework.web.bind.annotation.*;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 消息通知
 | 
			
		||||
 *
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05
 | 
			
		||||
 */
 | 
			
		||||
@Validated
 | 
			
		||||
@RestController
 | 
			
		||||
@RequestMapping("/message/notification")
 | 
			
		||||
public class MsgNotificationController extends BaseController {
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private IMsgNotificationService msgNotificationService;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 查询当前登录用户发送的消息通知列表
 | 
			
		||||
     */
 | 
			
		||||
    @SaCheckPermission("message:notification:listLoginSend")
 | 
			
		||||
    @GetMapping("/list/send/login")
 | 
			
		||||
    public TableDataInfo<MsgNotificationVo> listByLoginSend(MsgNotificationQueryReq req, PageQuery pageQuery) {
 | 
			
		||||
        Long userId = LoginHelper.getUserId();
 | 
			
		||||
        req.setSenderId(userId);
 | 
			
		||||
        return msgNotificationService.queryPageList(req, pageQuery);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 查询当前登录用户接收的消息通知列表
 | 
			
		||||
     */
 | 
			
		||||
    @SaCheckPermission("message:notification:listLoginRecipient")
 | 
			
		||||
    @GetMapping("/list/recipient/login")
 | 
			
		||||
    public TableDataInfo<MsgNotificationVo> listByLoginRecipient(MsgNotificationQueryReq req, PageQuery pageQuery) {
 | 
			
		||||
        Long userId = LoginHelper.getUserId();
 | 
			
		||||
        req.setRecipientId(userId);
 | 
			
		||||
        return msgNotificationService.queryPageList(req, pageQuery);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取消息通知详细信息
 | 
			
		||||
     *
 | 
			
		||||
     * @param id 主键
 | 
			
		||||
     */
 | 
			
		||||
    @SaCheckPermission("message:notification:query")
 | 
			
		||||
    @GetMapping("/{id}")
 | 
			
		||||
    public R<MsgNotificationVo> getInfo(@NotNull(message = "主键不能为空")
 | 
			
		||||
                                        @PathVariable Long id) {
 | 
			
		||||
        return R.ok(msgNotificationService.queryById(id));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 新增消息通知
 | 
			
		||||
     */
 | 
			
		||||
    @SaCheckPermission("message:notification:send")
 | 
			
		||||
    @Log(title = "消息通知", businessType = BusinessType.INSERT)
 | 
			
		||||
    @RepeatSubmit()
 | 
			
		||||
    @PostMapping("/send")
 | 
			
		||||
    public R<Void> sendMessage(@Validated @RequestBody MsgNotificationSendMessageReq req) {
 | 
			
		||||
        return toAjax(msgNotificationService.sendMessage(req));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 删除消息通知
 | 
			
		||||
     *
 | 
			
		||||
     * @param ids 主键串
 | 
			
		||||
     */
 | 
			
		||||
    @SaCheckPermission("message:notification:remove")
 | 
			
		||||
    @Log(title = "消息通知", businessType = BusinessType.DELETE)
 | 
			
		||||
    @DeleteMapping("/{ids}")
 | 
			
		||||
    public R<Void> remove(@NotEmpty(message = "主键不能为空")
 | 
			
		||||
                          @PathVariable Long[] ids) {
 | 
			
		||||
        return toAjax(msgNotificationService.deleteByIds(List.of(ids)));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,106 @@
 | 
			
		||||
package org.dromara.message.controller;
 | 
			
		||||
 | 
			
		||||
import cn.dev33.satoken.annotation.SaCheckPermission;
 | 
			
		||||
import jakarta.annotation.Resource;
 | 
			
		||||
import jakarta.servlet.http.HttpServletResponse;
 | 
			
		||||
import jakarta.validation.constraints.NotEmpty;
 | 
			
		||||
import jakarta.validation.constraints.NotNull;
 | 
			
		||||
import org.dromara.common.core.domain.R;
 | 
			
		||||
import org.dromara.common.excel.utils.ExcelUtil;
 | 
			
		||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
 | 
			
		||||
import org.dromara.common.log.annotation.Log;
 | 
			
		||||
import org.dromara.common.log.enums.BusinessType;
 | 
			
		||||
import org.dromara.common.mybatis.core.page.PageQuery;
 | 
			
		||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
 | 
			
		||||
import org.dromara.common.web.core.BaseController;
 | 
			
		||||
import org.dromara.message.domain.dto.notifytarget.MsgNotifyTargetCreateReq;
 | 
			
		||||
import org.dromara.message.domain.dto.notifytarget.MsgNotifyTargetQueryReq;
 | 
			
		||||
import org.dromara.message.domain.dto.notifytarget.MsgNotifyTargetUpdateReq;
 | 
			
		||||
import org.dromara.message.domain.vo.notifytarget.MsgNotifyTargetVo;
 | 
			
		||||
import org.dromara.message.service.IMsgNotifyTargetService;
 | 
			
		||||
import org.springframework.validation.annotation.Validated;
 | 
			
		||||
import org.springframework.web.bind.annotation.*;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 通知人员配置
 | 
			
		||||
 *
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05
 | 
			
		||||
 */
 | 
			
		||||
@Validated
 | 
			
		||||
@RestController
 | 
			
		||||
@RequestMapping("/message/notifyTarget")
 | 
			
		||||
public class MsgNotifyTargetController extends BaseController {
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private IMsgNotifyTargetService msgNotifyTargetService;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 查询通知人员配置列表
 | 
			
		||||
     */
 | 
			
		||||
    @SaCheckPermission("message:notifyTarget:list")
 | 
			
		||||
    @GetMapping("/list")
 | 
			
		||||
    public TableDataInfo<MsgNotifyTargetVo> list(MsgNotifyTargetQueryReq req, PageQuery pageQuery) {
 | 
			
		||||
        return msgNotifyTargetService.queryPageList(req, pageQuery);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 导出通知人员配置列表
 | 
			
		||||
     */
 | 
			
		||||
    @SaCheckPermission("message:notifyTarget:export")
 | 
			
		||||
    @Log(title = "通知人员配置", businessType = BusinessType.EXPORT)
 | 
			
		||||
    @PostMapping("/export")
 | 
			
		||||
    public void export(MsgNotifyTargetQueryReq req, HttpServletResponse response) {
 | 
			
		||||
        List<MsgNotifyTargetVo> list = msgNotifyTargetService.queryList(req);
 | 
			
		||||
        ExcelUtil.exportExcel(list, "通知人员配置", MsgNotifyTargetVo.class, response);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取通知人员配置详细信息
 | 
			
		||||
     *
 | 
			
		||||
     * @param id 主键
 | 
			
		||||
     */
 | 
			
		||||
    @SaCheckPermission("message:notifyTarget:query")
 | 
			
		||||
    @GetMapping("/{id}")
 | 
			
		||||
    public R<MsgNotifyTargetVo> getInfo(@NotNull(message = "主键不能为空")
 | 
			
		||||
                                        @PathVariable Long id) {
 | 
			
		||||
        return R.ok(msgNotifyTargetService.queryById(id));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 新增通知人员配置
 | 
			
		||||
     */
 | 
			
		||||
    @SaCheckPermission("message:notifyTarget:add")
 | 
			
		||||
    @Log(title = "通知人员配置", businessType = BusinessType.INSERT)
 | 
			
		||||
    @RepeatSubmit()
 | 
			
		||||
    @PostMapping()
 | 
			
		||||
    public R<Void> add(@Validated @RequestBody MsgNotifyTargetCreateReq req) {
 | 
			
		||||
        return toAjax(msgNotifyTargetService.insertByBo(req));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 修改通知人员配置
 | 
			
		||||
     */
 | 
			
		||||
    @SaCheckPermission("message:notifyTarget:edit")
 | 
			
		||||
    @Log(title = "通知人员配置", businessType = BusinessType.UPDATE)
 | 
			
		||||
    @RepeatSubmit()
 | 
			
		||||
    @PutMapping()
 | 
			
		||||
    public R<Void> edit(@Validated @RequestBody MsgNotifyTargetUpdateReq req) {
 | 
			
		||||
        return toAjax(msgNotifyTargetService.updateByBo(req));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 删除通知人员配置
 | 
			
		||||
     *
 | 
			
		||||
     * @param ids 主键串
 | 
			
		||||
     */
 | 
			
		||||
    @SaCheckPermission("message:notifyTarget:remove")
 | 
			
		||||
    @Log(title = "通知人员配置", businessType = BusinessType.DELETE)
 | 
			
		||||
    @DeleteMapping("/{ids}")
 | 
			
		||||
    public R<Void> remove(@NotEmpty(message = "主键不能为空")
 | 
			
		||||
                          @PathVariable Long[] ids) {
 | 
			
		||||
        return toAjax(msgNotifyTargetService.deleteByIds(List.of(ids)));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,105 @@
 | 
			
		||||
package org.dromara.message.controller;
 | 
			
		||||
 | 
			
		||||
import cn.dev33.satoken.annotation.SaCheckPermission;
 | 
			
		||||
import jakarta.annotation.Resource;
 | 
			
		||||
import jakarta.servlet.http.HttpServletResponse;
 | 
			
		||||
import jakarta.validation.constraints.NotEmpty;
 | 
			
		||||
import jakarta.validation.constraints.NotNull;
 | 
			
		||||
import org.dromara.common.core.domain.R;
 | 
			
		||||
import org.dromara.common.excel.utils.ExcelUtil;
 | 
			
		||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
 | 
			
		||||
import org.dromara.common.log.annotation.Log;
 | 
			
		||||
import org.dromara.common.log.enums.BusinessType;
 | 
			
		||||
import org.dromara.common.web.core.BaseController;
 | 
			
		||||
import org.dromara.message.domain.dto.typeconfig.MsgTypeConfigCreateReq;
 | 
			
		||||
import org.dromara.message.domain.dto.typeconfig.MsgTypeConfigQueryReq;
 | 
			
		||||
import org.dromara.message.domain.dto.typeconfig.MsgTypeConfigUpdateReq;
 | 
			
		||||
import org.dromara.message.domain.vo.typeconfig.MsgTypeConfigVo;
 | 
			
		||||
import org.dromara.message.service.IMsgTypeConfigService;
 | 
			
		||||
import org.springframework.validation.annotation.Validated;
 | 
			
		||||
import org.springframework.web.bind.annotation.*;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 消息类型配置
 | 
			
		||||
 *
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05
 | 
			
		||||
 */
 | 
			
		||||
@Validated
 | 
			
		||||
@RestController
 | 
			
		||||
@RequestMapping("/message/typeConfig")
 | 
			
		||||
public class MsgTypeConfigController extends BaseController {
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private IMsgTypeConfigService msgTypeConfigService;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 查询消息类型配置列表
 | 
			
		||||
     */
 | 
			
		||||
    @SaCheckPermission("message:typeConfig:list")
 | 
			
		||||
    @GetMapping("/list")
 | 
			
		||||
    public R<List<MsgTypeConfigVo>> list(MsgTypeConfigQueryReq req) {
 | 
			
		||||
        List<MsgTypeConfigVo> list = msgTypeConfigService.queryList(req);
 | 
			
		||||
        return R.ok(list);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 导出消息类型配置列表
 | 
			
		||||
     */
 | 
			
		||||
    @SaCheckPermission("message:typeConfig:export")
 | 
			
		||||
    @Log(title = "消息类型配置", businessType = BusinessType.EXPORT)
 | 
			
		||||
    @PostMapping("/export")
 | 
			
		||||
    public void export(MsgTypeConfigQueryReq req, HttpServletResponse response) {
 | 
			
		||||
        List<MsgTypeConfigVo> list = msgTypeConfigService.queryList(req);
 | 
			
		||||
        ExcelUtil.exportExcel(list, "消息类型配置", MsgTypeConfigVo.class, response);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取消息类型配置详细信息
 | 
			
		||||
     *
 | 
			
		||||
     * @param id 主键
 | 
			
		||||
     */
 | 
			
		||||
    @SaCheckPermission("message:typeConfig:query")
 | 
			
		||||
    @GetMapping("/{id}")
 | 
			
		||||
    public R<MsgTypeConfigVo> getInfo(@NotNull(message = "主键不能为空")
 | 
			
		||||
                                      @PathVariable Long id) {
 | 
			
		||||
        return R.ok(msgTypeConfigService.queryById(id));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 新增消息类型配置
 | 
			
		||||
     */
 | 
			
		||||
    @SaCheckPermission("message:typeConfig:add")
 | 
			
		||||
    @Log(title = "消息类型配置", businessType = BusinessType.INSERT)
 | 
			
		||||
    @RepeatSubmit()
 | 
			
		||||
    @PostMapping()
 | 
			
		||||
    public R<Long> add(@Validated @RequestBody MsgTypeConfigCreateReq req) {
 | 
			
		||||
        return R.ok(msgTypeConfigService.insertByBo(req));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 修改消息类型配置
 | 
			
		||||
     */
 | 
			
		||||
    @SaCheckPermission("message:typeConfig:edit")
 | 
			
		||||
    @Log(title = "消息类型配置", businessType = BusinessType.UPDATE)
 | 
			
		||||
    @RepeatSubmit()
 | 
			
		||||
    @PutMapping()
 | 
			
		||||
    public R<Void> edit(@Validated @RequestBody MsgTypeConfigUpdateReq req) {
 | 
			
		||||
        return toAjax(msgTypeConfigService.updateByBo(req));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 删除消息类型配置
 | 
			
		||||
     *
 | 
			
		||||
     * @param ids 主键串
 | 
			
		||||
     */
 | 
			
		||||
    @SaCheckPermission("message:typeConfig:remove")
 | 
			
		||||
    @Log(title = "消息类型配置", businessType = BusinessType.DELETE)
 | 
			
		||||
    @DeleteMapping("/{ids}")
 | 
			
		||||
    public R<Void> remove(@NotEmpty(message = "主键不能为空")
 | 
			
		||||
                          @PathVariable Long[] ids) {
 | 
			
		||||
        return toAjax(msgTypeConfigService.deleteByIds(List.of(ids)));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,95 @@
 | 
			
		||||
package org.dromara.message.domain;
 | 
			
		||||
 | 
			
		||||
import com.baomidou.mybatisplus.annotation.TableId;
 | 
			
		||||
import com.baomidou.mybatisplus.annotation.TableName;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
import java.io.Serial;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 消息通知对象 msg_notification
 | 
			
		||||
 *
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@TableName("msg_notification")
 | 
			
		||||
public class MsgNotification implements Serializable {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    private static final long serialVersionUID = 1L;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 主键ID
 | 
			
		||||
     */
 | 
			
		||||
    @TableId(value = "id")
 | 
			
		||||
    private Long id;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 项目ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long projectId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 接收通知的用户ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long recipientId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 发送通知的用户ID(系统通知 0)
 | 
			
		||||
     */
 | 
			
		||||
    private Long senderId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 通知类型ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long typeId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 通知标题
 | 
			
		||||
     */
 | 
			
		||||
    private String title;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 通知的主要内容
 | 
			
		||||
     */
 | 
			
		||||
    private String content;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 查看状态(0未读 1已读)
 | 
			
		||||
     */
 | 
			
		||||
    private String viewStatus;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 查看时间
 | 
			
		||||
     */
 | 
			
		||||
    private Date viewTime;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 点击通知后跳转的目标URL
 | 
			
		||||
     */
 | 
			
		||||
    private String actionUrl;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 通知附件
 | 
			
		||||
     */
 | 
			
		||||
    private String file;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 备注
 | 
			
		||||
     */
 | 
			
		||||
    private String remark;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 创建时间
 | 
			
		||||
     */
 | 
			
		||||
    private Date createTime;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 更新时间
 | 
			
		||||
     */
 | 
			
		||||
    private Date updateTime;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,51 @@
 | 
			
		||||
package org.dromara.message.domain;
 | 
			
		||||
 | 
			
		||||
import com.baomidou.mybatisplus.annotation.TableId;
 | 
			
		||||
import com.baomidou.mybatisplus.annotation.TableName;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.EqualsAndHashCode;
 | 
			
		||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
 | 
			
		||||
 | 
			
		||||
import java.io.Serial;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 通知人员配置对象 msg_notify_target
 | 
			
		||||
 *
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@EqualsAndHashCode(callSuper = true)
 | 
			
		||||
@TableName("msg_notify_target")
 | 
			
		||||
public class MsgNotifyTarget extends BaseEntity {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    private static final long serialVersionUID = 1L;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 主键ID
 | 
			
		||||
     */
 | 
			
		||||
    @TableId(value = "id")
 | 
			
		||||
    private Long id;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 项目ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long projectId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 消息类型ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long typeId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否启用(0正常 1禁用)
 | 
			
		||||
     */
 | 
			
		||||
    private String status;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 备注
 | 
			
		||||
     */
 | 
			
		||||
    private String remark;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,44 @@
 | 
			
		||||
package org.dromara.message.domain;
 | 
			
		||||
 | 
			
		||||
import com.baomidou.mybatisplus.annotation.TableId;
 | 
			
		||||
import com.baomidou.mybatisplus.annotation.TableName;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
import java.io.Serial;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 通知人员配置详情对象 msg_notify_target_detail
 | 
			
		||||
 *
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@TableName("msg_notify_target_detail")
 | 
			
		||||
public class MsgNotifyTargetDetail implements Serializable {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    private static final long serialVersionUID = 1L;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 主键ID
 | 
			
		||||
     */
 | 
			
		||||
    @TableId(value = "id")
 | 
			
		||||
    private Long id;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 消息类型配置ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long configId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 接收类型
 | 
			
		||||
     */
 | 
			
		||||
    private String targetType;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 接收ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long targetId;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,66 @@
 | 
			
		||||
package org.dromara.message.domain;
 | 
			
		||||
 | 
			
		||||
import com.baomidou.mybatisplus.annotation.TableId;
 | 
			
		||||
import com.baomidou.mybatisplus.annotation.TableName;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.EqualsAndHashCode;
 | 
			
		||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
 | 
			
		||||
 | 
			
		||||
import java.io.Serial;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 消息类型配置对象 msg_type_config
 | 
			
		||||
 *
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@EqualsAndHashCode(callSuper = true)
 | 
			
		||||
@TableName("msg_type_config")
 | 
			
		||||
public class MsgTypeConfig extends BaseEntity {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    private static final long serialVersionUID = 1L;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 主键ID
 | 
			
		||||
     */
 | 
			
		||||
    @TableId(value = "id")
 | 
			
		||||
    private Long id;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 项目ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long projectId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 父ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long parentId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 消息类型编码
 | 
			
		||||
     */
 | 
			
		||||
    private String typeCode;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 消息类型名称
 | 
			
		||||
     */
 | 
			
		||||
    private String typeName;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 消息类型描述
 | 
			
		||||
     */
 | 
			
		||||
    private String typeDesc;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否启用(0正常 1禁用)
 | 
			
		||||
     */
 | 
			
		||||
    private String status;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 备注
 | 
			
		||||
     */
 | 
			
		||||
    private String remark;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,47 @@
 | 
			
		||||
package org.dromara.message.domain.dto.notification;
 | 
			
		||||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
import java.io.Serial;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05 14:58
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
public class MsgNotificationQueryReq implements Serializable {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    private static final long serialVersionUID = 6297082509342761841L;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 项目ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long projectId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 接收通知的用户ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long recipientId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 发送通知的用户ID(系统通知 0)
 | 
			
		||||
     */
 | 
			
		||||
    private Long senderId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 通知类型ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long typeId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 通知标题
 | 
			
		||||
     */
 | 
			
		||||
    private String title;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 查看状态(0未读 1已读)
 | 
			
		||||
     */
 | 
			
		||||
    private String viewStatus;
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,64 @@
 | 
			
		||||
package org.dromara.message.domain.dto.notification;
 | 
			
		||||
 | 
			
		||||
import jakarta.validation.constraints.NotBlank;
 | 
			
		||||
import jakarta.validation.constraints.NotNull;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
import java.io.Serial;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05 15:04
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
public class MsgNotificationSendMessageReq implements Serializable {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    private static final long serialVersionUID = -3818662203023362981L;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 项目ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long projectId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 接收通知的用户ID
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull(message = "接收通知的用户ID不能为空")
 | 
			
		||||
    private Long recipientId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 通知类型ID
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull(message = "通知类型ID不能为空")
 | 
			
		||||
    private Long typeId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 通知标题
 | 
			
		||||
     */
 | 
			
		||||
    @NotBlank(message = "通知标题不能为空")
 | 
			
		||||
    private String title;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 通知的主要内容
 | 
			
		||||
     */
 | 
			
		||||
    @NotBlank(message = "通知主要内容不能为空")
 | 
			
		||||
    private String content;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 点击通知后跳转的目标URL
 | 
			
		||||
     */
 | 
			
		||||
    private String actionUrl;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 通知附件
 | 
			
		||||
     */
 | 
			
		||||
    private String file;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 备注
 | 
			
		||||
     */
 | 
			
		||||
    private String remark;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,50 @@
 | 
			
		||||
package org.dromara.message.domain.dto.notifytarget;
 | 
			
		||||
 | 
			
		||||
import jakarta.validation.constraints.NotEmpty;
 | 
			
		||||
import jakarta.validation.constraints.NotNull;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import org.dromara.message.domain.dto.notifytargetdetail.MsgNotifyTargetDetailCreateDto;
 | 
			
		||||
 | 
			
		||||
import java.io.Serial;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05 16:14
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
public class MsgNotifyTargetCreateReq implements Serializable {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    private static final long serialVersionUID = 6726656627774354043L;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 项目ID
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull(message = "项目ID不能为空")
 | 
			
		||||
    private Long projectId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 消息类型ID
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull(message = "消息类型ID不能为空")
 | 
			
		||||
    private Long typeId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 通知人员配置详情列表
 | 
			
		||||
     */
 | 
			
		||||
    @NotEmpty(message = "通知人员配置详情列表不能为空")
 | 
			
		||||
    private List<MsgNotifyTargetDetailCreateDto> detailList;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否启用(0正常 1禁用)
 | 
			
		||||
     */
 | 
			
		||||
    private String status;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 备注
 | 
			
		||||
     */
 | 
			
		||||
    private String remark;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,33 @@
 | 
			
		||||
package org.dromara.message.domain.dto.notifytarget;
 | 
			
		||||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
import java.io.Serial;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05 16:14
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
public class MsgNotifyTargetQueryReq implements Serializable {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    private static final long serialVersionUID = -1555802564920782912L;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 项目ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long projectId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 消息类型ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long typeId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否启用(0正常 1禁用)
 | 
			
		||||
     */
 | 
			
		||||
    private String status;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,54 @@
 | 
			
		||||
package org.dromara.message.domain.dto.notifytarget;
 | 
			
		||||
 | 
			
		||||
import jakarta.validation.constraints.NotEmpty;
 | 
			
		||||
import jakarta.validation.constraints.NotNull;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import org.dromara.message.domain.dto.notifytargetdetail.MsgNotifyTargetDetailUpdateDto;
 | 
			
		||||
 | 
			
		||||
import java.io.Serial;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05 16:15
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
public class MsgNotifyTargetUpdateReq implements Serializable {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    private static final long serialVersionUID = -8315266866313669088L;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 主键ID
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull(message = "主键ID不能为空")
 | 
			
		||||
    private Long id;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 项目ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long projectId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 消息类型ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long typeId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 通知人员配置详情列表
 | 
			
		||||
     */
 | 
			
		||||
    @NotEmpty(message = "通知人员配置详情列表不能为空")
 | 
			
		||||
    private List<MsgNotifyTargetDetailUpdateDto> detailList;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否启用(0正常 1禁用)
 | 
			
		||||
     */
 | 
			
		||||
    private String status;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 备注
 | 
			
		||||
     */
 | 
			
		||||
    private String remark;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,26 @@
 | 
			
		||||
package org.dromara.message.domain.dto.notifytargetdetail;
 | 
			
		||||
 | 
			
		||||
import lombok.AllArgsConstructor;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.NoArgsConstructor;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05 17:34
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@NoArgsConstructor
 | 
			
		||||
@AllArgsConstructor
 | 
			
		||||
public class MsgNotifyTargetDetailCreateDto {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 接收类型
 | 
			
		||||
     */
 | 
			
		||||
    private String targetType;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 接收ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long targetId;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,32 @@
 | 
			
		||||
package org.dromara.message.domain.dto.notifytargetdetail;
 | 
			
		||||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05 18:54
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
public class MsgNotifyTargetDetailUpdateDto {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 主键ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long id;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 消息类型配置ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long configId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 接收类型
 | 
			
		||||
     */
 | 
			
		||||
    private String targetType;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 接收ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long targetId;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,59 @@
 | 
			
		||||
package org.dromara.message.domain.dto.typeconfig;
 | 
			
		||||
 | 
			
		||||
import jakarta.validation.constraints.NotBlank;
 | 
			
		||||
import jakarta.validation.constraints.NotEmpty;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import org.dromara.message.domain.dto.notifytargetdetail.MsgNotifyTargetDetailCreateDto;
 | 
			
		||||
 | 
			
		||||
import java.io.Serial;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05 11:55
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
public class MsgTypeConfigCreateReq implements Serializable {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    private static final long serialVersionUID = 7200792696273923100L;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 项目ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long projectId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 父ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long parentId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 消息类型编码
 | 
			
		||||
     */
 | 
			
		||||
    @NotBlank(message = "消息类型编码不能为空")
 | 
			
		||||
    private String typeCode;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 消息类型名称
 | 
			
		||||
     */
 | 
			
		||||
    @NotBlank(message = "消息类型名称不能为空")
 | 
			
		||||
    private String typeName;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 消息类型描述
 | 
			
		||||
     */
 | 
			
		||||
    private String typeDesc;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否启用(0正常 1禁用)
 | 
			
		||||
     */
 | 
			
		||||
    private String status;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 备注
 | 
			
		||||
     */
 | 
			
		||||
    private String remark;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,42 @@
 | 
			
		||||
package org.dromara.message.domain.dto.typeconfig;
 | 
			
		||||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
import java.io.Serial;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05 11:56
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
public class MsgTypeConfigQueryReq implements Serializable {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    private static final long serialVersionUID = 4107391817233057971L;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 项目ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long projectId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 父ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long parentId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 消息类型编码
 | 
			
		||||
     */
 | 
			
		||||
    private String typeCode;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 消息类型名称
 | 
			
		||||
     */
 | 
			
		||||
    private String typeName;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否启用(0正常 1禁用)
 | 
			
		||||
     */
 | 
			
		||||
    private String status;
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,55 @@
 | 
			
		||||
package org.dromara.message.domain.dto.typeconfig;
 | 
			
		||||
 | 
			
		||||
import jakarta.validation.constraints.NotNull;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
import java.io.Serial;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05 11:55
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
public class MsgTypeConfigUpdateReq implements Serializable {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    private static final long serialVersionUID = -9036270979980317352L;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 主键ID
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull(message = "主键ID不能为空")
 | 
			
		||||
    private Long id;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 父ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long parentId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 消息类型编码
 | 
			
		||||
     */
 | 
			
		||||
    private String typeCode;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 消息类型名称
 | 
			
		||||
     */
 | 
			
		||||
    private String typeName;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 消息类型描述
 | 
			
		||||
     */
 | 
			
		||||
    private String typeDesc;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否启用(0正常 1禁用)
 | 
			
		||||
     */
 | 
			
		||||
    private String status;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 备注
 | 
			
		||||
     */
 | 
			
		||||
    private String remark;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,25 @@
 | 
			
		||||
package org.dromara.message.domain.enums;
 | 
			
		||||
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05 16:47
 | 
			
		||||
 */
 | 
			
		||||
@Getter
 | 
			
		||||
public enum MsgMessageTargetType {
 | 
			
		||||
 | 
			
		||||
    USER("用户", "1"),
 | 
			
		||||
    ROLE("角色", "2"),
 | 
			
		||||
    DEPT("部门", "3");
 | 
			
		||||
 | 
			
		||||
    private final String text;
 | 
			
		||||
 | 
			
		||||
    private final String value;
 | 
			
		||||
 | 
			
		||||
    MsgMessageTargetType(String text, String value) {
 | 
			
		||||
        this.text = text;
 | 
			
		||||
        this.value = value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,24 @@
 | 
			
		||||
package org.dromara.message.domain.enums;
 | 
			
		||||
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05 15:39
 | 
			
		||||
 */
 | 
			
		||||
@Getter
 | 
			
		||||
public enum MsgMessageViewStatus {
 | 
			
		||||
 | 
			
		||||
    NO("未读", "0"),
 | 
			
		||||
    YSE("已读", "1");
 | 
			
		||||
 | 
			
		||||
    private final String text;
 | 
			
		||||
 | 
			
		||||
    private final String value;
 | 
			
		||||
 | 
			
		||||
    MsgMessageViewStatus(String text, String value) {
 | 
			
		||||
        this.text = text;
 | 
			
		||||
        this.value = value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,108 @@
 | 
			
		||||
package org.dromara.message.domain.vo.notification;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
 | 
			
		||||
import com.alibaba.excel.annotation.ExcelProperty;
 | 
			
		||||
import io.github.linpeilie.annotations.AutoMapper;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import org.dromara.common.excel.annotation.ExcelDictFormat;
 | 
			
		||||
import org.dromara.common.excel.convert.ExcelDictConvert;
 | 
			
		||||
import org.dromara.message.domain.MsgNotification;
 | 
			
		||||
 | 
			
		||||
import java.io.Serial;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 消息通知视图对象 msg_notification
 | 
			
		||||
 *
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@ExcelIgnoreUnannotated
 | 
			
		||||
@AutoMapper(target = MsgNotification.class)
 | 
			
		||||
public class MsgNotificationVo implements Serializable {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    private static final long serialVersionUID = 1L;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 主键ID
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelProperty(value = "主键ID")
 | 
			
		||||
    private Long id;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 项目ID
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelProperty(value = "项目ID")
 | 
			
		||||
    private Long projectId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 接收通知的用户ID
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelProperty(value = "接收通知的用户ID")
 | 
			
		||||
    private Long recipientId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 发送通知的用户ID(系统通知 0)
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelProperty(value = "发送通知的用户ID")
 | 
			
		||||
    private Long senderId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 发送通知的用户名称
 | 
			
		||||
     */
 | 
			
		||||
    private String senderName;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 通知类型ID
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelProperty(value = "通知类型ID")
 | 
			
		||||
    private Long typeId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 通知标题
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelProperty(value = "通知标题")
 | 
			
		||||
    private String title;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 通知的主要内容
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelProperty(value = "通知的主要内容")
 | 
			
		||||
    private String content;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 查看状态(0未读 1已读)
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelProperty(value = "查看状态(0未读 1已读)", converter = ExcelDictConvert.class)
 | 
			
		||||
    @ExcelDictFormat(dictType = "view_status")
 | 
			
		||||
    private String viewStatus;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 查看时间
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelProperty(value = "查看时间")
 | 
			
		||||
    private Date viewTime;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 点击通知后跳转的目标URL
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelProperty(value = "点击通知后跳转的目标URL")
 | 
			
		||||
    private String actionUrl;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 通知附件
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelProperty(value = "通知附件")
 | 
			
		||||
    private String file;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 备注
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelProperty(value = "备注")
 | 
			
		||||
    private String remark;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,67 @@
 | 
			
		||||
package org.dromara.message.domain.vo.notifytarget;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
 | 
			
		||||
import com.alibaba.excel.annotation.ExcelProperty;
 | 
			
		||||
import io.github.linpeilie.annotations.AutoMapper;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import org.dromara.common.excel.annotation.ExcelDictFormat;
 | 
			
		||||
import org.dromara.common.excel.convert.ExcelDictConvert;
 | 
			
		||||
import org.dromara.message.domain.MsgNotifyTarget;
 | 
			
		||||
import org.dromara.message.domain.vo.notifytargetdetail.MsgNotifyTargetDetailVo;
 | 
			
		||||
 | 
			
		||||
import java.io.Serial;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 通知人员配置视图对象 msg_notify_target
 | 
			
		||||
 *
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@ExcelIgnoreUnannotated
 | 
			
		||||
@AutoMapper(target = MsgNotifyTarget.class)
 | 
			
		||||
public class MsgNotifyTargetVo implements Serializable {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    private static final long serialVersionUID = 1L;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 主键ID
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelProperty(value = "主键ID")
 | 
			
		||||
    private Long id;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 项目ID
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelProperty(value = "项目ID")
 | 
			
		||||
    private Long projectId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 消息类型ID
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelProperty(value = "消息类型ID")
 | 
			
		||||
    private Long typeId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 通知人员配置详情列表
 | 
			
		||||
     */
 | 
			
		||||
    private List<MsgNotifyTargetDetailVo> detailList;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否启用(0正常 1禁用)
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelProperty(value = "是否启用(0正常 1禁用)", converter = ExcelDictConvert.class)
 | 
			
		||||
    @ExcelDictFormat(dictType = "sys_notice_status")
 | 
			
		||||
    private String status;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 备注
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelProperty(value = "备注")
 | 
			
		||||
    private String remark;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,49 @@
 | 
			
		||||
package org.dromara.message.domain.vo.notifytargetdetail;
 | 
			
		||||
 | 
			
		||||
import io.github.linpeilie.annotations.AutoMapper;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import org.dromara.message.domain.MsgNotifyTargetDetail;
 | 
			
		||||
 | 
			
		||||
import java.io.Serial;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 通知人员配置详情视图对象 msg_notify_target_detail
 | 
			
		||||
 *
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@AutoMapper(target = MsgNotifyTargetDetail.class)
 | 
			
		||||
public class MsgNotifyTargetDetailVo implements Serializable {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    private static final long serialVersionUID = 1L;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 主键ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long id;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 消息类型配置ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long configId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 接收类型
 | 
			
		||||
     */
 | 
			
		||||
    private String targetType;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 接收ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long targetId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 接收名称
 | 
			
		||||
     */
 | 
			
		||||
    private String targetName;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,78 @@
 | 
			
		||||
package org.dromara.message.domain.vo.typeconfig;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
 | 
			
		||||
import com.alibaba.excel.annotation.ExcelProperty;
 | 
			
		||||
import io.github.linpeilie.annotations.AutoMapper;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import org.dromara.common.excel.annotation.ExcelDictFormat;
 | 
			
		||||
import org.dromara.common.excel.convert.ExcelDictConvert;
 | 
			
		||||
import org.dromara.message.domain.MsgTypeConfig;
 | 
			
		||||
 | 
			
		||||
import java.io.Serial;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 消息类型配置视图对象 msg_type_config
 | 
			
		||||
 *
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@ExcelIgnoreUnannotated
 | 
			
		||||
@AutoMapper(target = MsgTypeConfig.class)
 | 
			
		||||
public class MsgTypeConfigVo implements Serializable {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    private static final long serialVersionUID = 1L;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 主键ID
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelProperty(value = "主键ID")
 | 
			
		||||
    private Long id;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 项目ID
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelProperty(value = "项目ID")
 | 
			
		||||
    private Long projectId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 父ID
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelProperty(value = "父ID")
 | 
			
		||||
    private Long parentId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 消息类型编码
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelProperty(value = "消息类型编码")
 | 
			
		||||
    private String typeCode;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 消息类型名称
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelProperty(value = "消息类型名称")
 | 
			
		||||
    private String typeName;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 消息类型描述
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelProperty(value = "消息类型描述")
 | 
			
		||||
    private String typeDesc;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否启用(0正常 1禁用)
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelProperty(value = "是否启用(0正常 1禁用)", converter = ExcelDictConvert.class)
 | 
			
		||||
    @ExcelDictFormat(dictType = "sys_notice_status")
 | 
			
		||||
    private String status;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 备注
 | 
			
		||||
     */
 | 
			
		||||
    @ExcelProperty(value = "备注")
 | 
			
		||||
    private String remark;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,15 @@
 | 
			
		||||
package org.dromara.message.mapper;
 | 
			
		||||
 | 
			
		||||
import org.dromara.message.domain.MsgNotification;
 | 
			
		||||
import org.dromara.message.domain.vo.notification.MsgNotificationVo;
 | 
			
		||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 消息通知Mapper接口
 | 
			
		||||
 *
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05
 | 
			
		||||
 */
 | 
			
		||||
public interface MsgNotificationMapper extends BaseMapperPlus<MsgNotification, MsgNotificationVo> {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,15 @@
 | 
			
		||||
package org.dromara.message.mapper;
 | 
			
		||||
 | 
			
		||||
import org.dromara.message.domain.MsgNotifyTargetDetail;
 | 
			
		||||
import org.dromara.message.domain.vo.notifytargetdetail.MsgNotifyTargetDetailVo;
 | 
			
		||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 通知人员配置详情Mapper接口
 | 
			
		||||
 *
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05
 | 
			
		||||
 */
 | 
			
		||||
public interface MsgNotifyTargetDetailMapper extends BaseMapperPlus<MsgNotifyTargetDetail, MsgNotifyTargetDetailVo> {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,15 @@
 | 
			
		||||
package org.dromara.message.mapper;
 | 
			
		||||
 | 
			
		||||
import org.dromara.message.domain.MsgNotifyTarget;
 | 
			
		||||
import org.dromara.message.domain.vo.notifytarget.MsgNotifyTargetVo;
 | 
			
		||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 通知人员配置Mapper接口
 | 
			
		||||
 *
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05
 | 
			
		||||
 */
 | 
			
		||||
public interface MsgNotifyTargetMapper extends BaseMapperPlus<MsgNotifyTarget, MsgNotifyTargetVo> {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,15 @@
 | 
			
		||||
package org.dromara.message.mapper;
 | 
			
		||||
 | 
			
		||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
 | 
			
		||||
import org.dromara.message.domain.MsgTypeConfig;
 | 
			
		||||
import org.dromara.message.domain.vo.typeconfig.MsgTypeConfigVo;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 消息类型配置Mapper接口
 | 
			
		||||
 *
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05
 | 
			
		||||
 */
 | 
			
		||||
public interface MsgTypeConfigMapper extends BaseMapperPlus<MsgTypeConfig, MsgTypeConfigVo> {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,96 @@
 | 
			
		||||
package org.dromara.message.service;
 | 
			
		||||
 | 
			
		||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 | 
			
		||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 | 
			
		||||
import com.baomidou.mybatisplus.extension.service.IService;
 | 
			
		||||
import org.dromara.common.mybatis.core.page.PageQuery;
 | 
			
		||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
 | 
			
		||||
import org.dromara.message.domain.MsgNotification;
 | 
			
		||||
import org.dromara.message.domain.dto.notification.MsgNotificationQueryReq;
 | 
			
		||||
import org.dromara.message.domain.dto.notification.MsgNotificationSendMessageReq;
 | 
			
		||||
import org.dromara.message.domain.vo.notification.MsgNotificationVo;
 | 
			
		||||
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 消息通知Service接口
 | 
			
		||||
 *
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05
 | 
			
		||||
 */
 | 
			
		||||
public interface IMsgNotificationService extends IService<MsgNotification> {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 校验消息通知权限
 | 
			
		||||
     *
 | 
			
		||||
     * @param userId       用户ID
 | 
			
		||||
     * @param notification 消息通知
 | 
			
		||||
     */
 | 
			
		||||
    void validHasPermission(Long userId, MsgNotification notification);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 查询消息通知
 | 
			
		||||
     *
 | 
			
		||||
     * @param id 主键
 | 
			
		||||
     * @return 消息通知
 | 
			
		||||
     */
 | 
			
		||||
    MsgNotificationVo queryById(Long id);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 分页查询消息通知列表
 | 
			
		||||
     *
 | 
			
		||||
     * @param req       查询条件
 | 
			
		||||
     * @param pageQuery 分页参数
 | 
			
		||||
     * @return 消息通知分页列表
 | 
			
		||||
     */
 | 
			
		||||
    TableDataInfo<MsgNotificationVo> queryPageList(MsgNotificationQueryReq req, PageQuery pageQuery);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 查询符合条件的消息通知列表
 | 
			
		||||
     *
 | 
			
		||||
     * @param req 查询条件
 | 
			
		||||
     * @return 消息通知列表
 | 
			
		||||
     */
 | 
			
		||||
    List<MsgNotificationVo> queryList(MsgNotificationQueryReq req);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 发送消息通知
 | 
			
		||||
     *
 | 
			
		||||
     * @param req 消息通知
 | 
			
		||||
     * @return 是否发送成功
 | 
			
		||||
     */
 | 
			
		||||
    Boolean sendMessage(MsgNotificationSendMessageReq req);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 批量删除消息通知信息
 | 
			
		||||
     *
 | 
			
		||||
     * @param ids 待删除的主键集合
 | 
			
		||||
     * @return 是否删除成功
 | 
			
		||||
     */
 | 
			
		||||
    Boolean deleteByIds(Collection<Long> ids);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取消息通知视图对象
 | 
			
		||||
     *
 | 
			
		||||
     * @param notification 消息通知对象
 | 
			
		||||
     * @return 消息通知视图对象
 | 
			
		||||
     */
 | 
			
		||||
    MsgNotificationVo getVo(MsgNotification notification);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取消息通知查询条件封装
 | 
			
		||||
     *
 | 
			
		||||
     * @param req 查询条件
 | 
			
		||||
     * @return 查询条件封装
 | 
			
		||||
     */
 | 
			
		||||
    LambdaQueryWrapper<MsgNotification> buildQueryWrapper(MsgNotificationQueryReq req);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取消息通知分页对象视图
 | 
			
		||||
     *
 | 
			
		||||
     * @param notificationPage 消息通知分页对象
 | 
			
		||||
     * @return 消息通知分页详情对象视图
 | 
			
		||||
     */
 | 
			
		||||
    Page<MsgNotificationVo> getVoPage(Page<MsgNotification> notificationPage);
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,49 @@
 | 
			
		||||
package org.dromara.message.service;
 | 
			
		||||
 | 
			
		||||
import com.baomidou.mybatisplus.extension.service.IService;
 | 
			
		||||
import org.dromara.message.domain.MsgNotifyTargetDetail;
 | 
			
		||||
import org.dromara.message.domain.vo.notifytargetdetail.MsgNotifyTargetDetailVo;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 通知人员配置详情Service接口
 | 
			
		||||
 *
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05
 | 
			
		||||
 */
 | 
			
		||||
public interface IMsgNotifyTargetDetailService extends IService<MsgNotifyTargetDetail> {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 根据通知目标ID查询用户ID列表
 | 
			
		||||
     *
 | 
			
		||||
     * @param targetId 通知目标ID
 | 
			
		||||
     * @return 用户ID列表
 | 
			
		||||
     */
 | 
			
		||||
    List<Long> queryUserIdsByTargetId(Long targetId);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 根据通知目标ID查询通知目标详情列表
 | 
			
		||||
     *
 | 
			
		||||
     * @param targetId 通知目标ID
 | 
			
		||||
     * @return 通知目标详情列表
 | 
			
		||||
     */
 | 
			
		||||
    List<MsgNotifyTargetDetailVo> queryVoListByTargetId(Long targetId);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取通知人员配置详情封装
 | 
			
		||||
     *
 | 
			
		||||
     * @param detail 通知人员配置详情
 | 
			
		||||
     * @return 通知人员配置详情封装
 | 
			
		||||
     */
 | 
			
		||||
    MsgNotifyTargetDetailVo getVo(MsgNotifyTargetDetail detail);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 批量获取通知人员配置详情封装
 | 
			
		||||
     *
 | 
			
		||||
     * @param detailList 通知人员配置详情列表
 | 
			
		||||
     * @return 通知人员配置详情封装列表
 | 
			
		||||
     */
 | 
			
		||||
    List<MsgNotifyTargetDetailVo> getVoList(List<MsgNotifyTargetDetail> detailList);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,97 @@
 | 
			
		||||
package org.dromara.message.service;
 | 
			
		||||
 | 
			
		||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 | 
			
		||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 | 
			
		||||
import com.baomidou.mybatisplus.extension.service.IService;
 | 
			
		||||
import org.dromara.common.mybatis.core.page.PageQuery;
 | 
			
		||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
 | 
			
		||||
import org.dromara.message.domain.MsgNotifyTarget;
 | 
			
		||||
import org.dromara.message.domain.dto.notifytarget.MsgNotifyTargetCreateReq;
 | 
			
		||||
import org.dromara.message.domain.dto.notifytarget.MsgNotifyTargetQueryReq;
 | 
			
		||||
import org.dromara.message.domain.dto.notifytarget.MsgNotifyTargetUpdateReq;
 | 
			
		||||
import org.dromara.message.domain.vo.notifytarget.MsgNotifyTargetVo;
 | 
			
		||||
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 通知人员配置Service接口
 | 
			
		||||
 *
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05
 | 
			
		||||
 */
 | 
			
		||||
public interface IMsgNotifyTargetService extends IService<MsgNotifyTarget> {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 查询通知人员配置
 | 
			
		||||
     *
 | 
			
		||||
     * @param id 主键
 | 
			
		||||
     * @return 通知人员配置
 | 
			
		||||
     */
 | 
			
		||||
    MsgNotifyTargetVo queryById(Long id);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 分页查询通知人员配置列表
 | 
			
		||||
     *
 | 
			
		||||
     * @param req       查询条件
 | 
			
		||||
     * @param pageQuery 分页参数
 | 
			
		||||
     * @return 通知人员配置分页列表
 | 
			
		||||
     */
 | 
			
		||||
    TableDataInfo<MsgNotifyTargetVo> queryPageList(MsgNotifyTargetQueryReq req, PageQuery pageQuery);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 查询符合条件的通知人员配置列表
 | 
			
		||||
     *
 | 
			
		||||
     * @param req 查询条件
 | 
			
		||||
     * @return 通知人员配置列表
 | 
			
		||||
     */
 | 
			
		||||
    List<MsgNotifyTargetVo> queryList(MsgNotifyTargetQueryReq req);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 新增通知人员配置
 | 
			
		||||
     *
 | 
			
		||||
     * @param req 通知人员配置
 | 
			
		||||
     * @return 是否新增成功
 | 
			
		||||
     */
 | 
			
		||||
    Boolean insertByBo(MsgNotifyTargetCreateReq req);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 修改通知人员配置
 | 
			
		||||
     *
 | 
			
		||||
     * @param req 通知人员配置
 | 
			
		||||
     * @return 是否修改成功
 | 
			
		||||
     */
 | 
			
		||||
    Boolean updateByBo(MsgNotifyTargetUpdateReq req);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 批量删除通知人员配置信息
 | 
			
		||||
     *
 | 
			
		||||
     * @param ids 待删除的主键集合
 | 
			
		||||
     * @return 是否删除成功
 | 
			
		||||
     */
 | 
			
		||||
    Boolean deleteByIds(Collection<Long> ids);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取通知人员配置视图对象
 | 
			
		||||
     *
 | 
			
		||||
     * @param notifyTarget 通知人员配置对象
 | 
			
		||||
     * @return 通知人员配置视图对象
 | 
			
		||||
     */
 | 
			
		||||
    MsgNotifyTargetVo getVo(MsgNotifyTarget notifyTarget);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取通知人员配置查询条件封装
 | 
			
		||||
     *
 | 
			
		||||
     * @param req 查询条件
 | 
			
		||||
     * @return 查询条件封装
 | 
			
		||||
     */
 | 
			
		||||
    LambdaQueryWrapper<MsgNotifyTarget> buildQueryWrapper(MsgNotifyTargetQueryReq req);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取通知人员配置分页对象视图
 | 
			
		||||
     *
 | 
			
		||||
     * @param notifyTargetPage 通知人员配置分页对象
 | 
			
		||||
     * @return 通知人员配置分页详情对象视图
 | 
			
		||||
     */
 | 
			
		||||
    Page<MsgNotifyTargetVo> getVoPage(Page<MsgNotifyTarget> notifyTargetPage);
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,86 @@
 | 
			
		||||
package org.dromara.message.service;
 | 
			
		||||
 | 
			
		||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 | 
			
		||||
import com.baomidou.mybatisplus.extension.service.IService;
 | 
			
		||||
import org.dromara.message.domain.MsgTypeConfig;
 | 
			
		||||
import org.dromara.message.domain.dto.typeconfig.MsgTypeConfigCreateReq;
 | 
			
		||||
import org.dromara.message.domain.dto.typeconfig.MsgTypeConfigQueryReq;
 | 
			
		||||
import org.dromara.message.domain.dto.typeconfig.MsgTypeConfigUpdateReq;
 | 
			
		||||
import org.dromara.message.domain.vo.typeconfig.MsgTypeConfigVo;
 | 
			
		||||
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 消息类型配置Service接口
 | 
			
		||||
 *
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05
 | 
			
		||||
 */
 | 
			
		||||
public interface IMsgTypeConfigService extends IService<MsgTypeConfig> {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 查询消息类型配置
 | 
			
		||||
     *
 | 
			
		||||
     * @param id 主键
 | 
			
		||||
     * @return 消息类型配置
 | 
			
		||||
     */
 | 
			
		||||
    MsgTypeConfigVo queryById(Long id);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 查询符合条件的消息类型配置列表
 | 
			
		||||
     *
 | 
			
		||||
     * @param req 查询条件
 | 
			
		||||
     * @return 消息类型配置列表
 | 
			
		||||
     */
 | 
			
		||||
    List<MsgTypeConfigVo> queryList(MsgTypeConfigQueryReq req);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 新增消息类型配置
 | 
			
		||||
     *
 | 
			
		||||
     * @param req 消息类型配置
 | 
			
		||||
     * @return 新增成功消息类型配置id
 | 
			
		||||
     */
 | 
			
		||||
    Long insertByBo(MsgTypeConfigCreateReq req);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 修改消息类型配置
 | 
			
		||||
     *
 | 
			
		||||
     * @param req 消息类型配置
 | 
			
		||||
     * @return 是否修改成功
 | 
			
		||||
     */
 | 
			
		||||
    Boolean updateByBo(MsgTypeConfigUpdateReq req);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 批量删除消息类型配置信息
 | 
			
		||||
     *
 | 
			
		||||
     * @param ids 待删除的主键集合
 | 
			
		||||
     * @return 是否删除成功
 | 
			
		||||
     */
 | 
			
		||||
    Boolean deleteByIds(Collection<Long> ids);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取消息类型配置视图对象
 | 
			
		||||
     *
 | 
			
		||||
     * @param typeConfig 消息类型配置对象
 | 
			
		||||
     * @return 消息类型配置视图对象
 | 
			
		||||
     */
 | 
			
		||||
    MsgTypeConfigVo getVo(MsgTypeConfig typeConfig);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取消息类型配置查询条件封装
 | 
			
		||||
     *
 | 
			
		||||
     * @param req 查询条件
 | 
			
		||||
     * @return 查询条件封装
 | 
			
		||||
     */
 | 
			
		||||
    LambdaQueryWrapper<MsgTypeConfig> buildQueryWrapper(MsgTypeConfigQueryReq req);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取消息类型配置分页对象视图
 | 
			
		||||
     *
 | 
			
		||||
     * @param typeConfigList 消息类型配置分页对象
 | 
			
		||||
     * @return 消息类型配置分页对象视图
 | 
			
		||||
     */
 | 
			
		||||
    List<MsgTypeConfigVo> getVoList(List<MsgTypeConfig> typeConfigList);
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,280 @@
 | 
			
		||||
package org.dromara.message.service.impl;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.collection.CollUtil;
 | 
			
		||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 | 
			
		||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 | 
			
		||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 | 
			
		||||
import jakarta.annotation.Resource;
 | 
			
		||||
import org.dromara.common.core.constant.HttpStatus;
 | 
			
		||||
import org.dromara.common.core.exception.ServiceException;
 | 
			
		||||
import org.dromara.common.core.utils.ObjectUtils;
 | 
			
		||||
import org.dromara.common.core.utils.StringUtils;
 | 
			
		||||
import org.dromara.common.mybatis.core.page.PageQuery;
 | 
			
		||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
 | 
			
		||||
import org.dromara.common.satoken.utils.LoginHelper;
 | 
			
		||||
import org.dromara.common.sse.dto.SseMessageDto;
 | 
			
		||||
import org.dromara.common.sse.utils.SseMessageUtils;
 | 
			
		||||
import org.dromara.message.domain.MsgNotification;
 | 
			
		||||
import org.dromara.message.domain.MsgTypeConfig;
 | 
			
		||||
import org.dromara.message.domain.dto.notification.MsgNotificationQueryReq;
 | 
			
		||||
import org.dromara.message.domain.dto.notification.MsgNotificationSendMessageReq;
 | 
			
		||||
import org.dromara.message.domain.enums.MsgMessageViewStatus;
 | 
			
		||||
import org.dromara.message.domain.vo.notification.MsgNotificationVo;
 | 
			
		||||
import org.dromara.message.mapper.MsgNotificationMapper;
 | 
			
		||||
import org.dromara.message.service.IMsgNotificationService;
 | 
			
		||||
import org.dromara.message.service.IMsgTypeConfigService;
 | 
			
		||||
import org.dromara.system.domain.vo.SysUserVo;
 | 
			
		||||
import org.dromara.system.service.ISysUserService;
 | 
			
		||||
import org.springframework.beans.BeanUtils;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
import org.springframework.transaction.annotation.Transactional;
 | 
			
		||||
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 消息通知Service业务层处理
 | 
			
		||||
 *
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05
 | 
			
		||||
 */
 | 
			
		||||
@Service
 | 
			
		||||
public class MsgNotificationServiceImpl extends ServiceImpl<MsgNotificationMapper, MsgNotification>
 | 
			
		||||
    implements IMsgNotificationService {
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private ISysUserService userService;
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private IMsgTypeConfigService typeConfigService;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 校验消息通知权限
 | 
			
		||||
     *
 | 
			
		||||
     * @param userId       用户ID
 | 
			
		||||
     * @param notification 消息通知
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void validHasPermission(Long userId, MsgNotification notification) {
 | 
			
		||||
        Long senderId = notification.getSenderId();
 | 
			
		||||
        Long recipientId = notification.getRecipientId();
 | 
			
		||||
        if ((senderId == 0 && !userId.equals(recipientId))
 | 
			
		||||
            || (senderId != 0 && !userId.equals(senderId) && !userId.equals(recipientId))) {
 | 
			
		||||
            throw new ServiceException("无权限处理此消息通知", HttpStatus.FORBIDDEN);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 查询消息通知
 | 
			
		||||
     *
 | 
			
		||||
     * @param id 主键
 | 
			
		||||
     * @return 消息通知
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public MsgNotificationVo queryById(Long id) {
 | 
			
		||||
        MsgNotification notification = this.getById(id);
 | 
			
		||||
        if (notification == null) {
 | 
			
		||||
            throw new ServiceException("消息通知信息不存在", HttpStatus.NOT_FOUND);
 | 
			
		||||
        }
 | 
			
		||||
        Long userId = LoginHelper.getUserId();
 | 
			
		||||
        if (userId == null) {
 | 
			
		||||
            throw new ServiceException("未获取到用户信息", HttpStatus.UNAUTHORIZED);
 | 
			
		||||
        }
 | 
			
		||||
        // 校验权限
 | 
			
		||||
        validHasPermission(userId, notification);
 | 
			
		||||
        // 如果为消息接收方,则修改状态为已阅读
 | 
			
		||||
        if (userId.equals(notification.getRecipientId()) && notification.getViewStatus().equals(MsgMessageViewStatus.NO.getValue())) {
 | 
			
		||||
            notification.setViewStatus(MsgMessageViewStatus.YSE.getValue());
 | 
			
		||||
            notification.setViewTime(new Date());
 | 
			
		||||
            this.updateById(notification);
 | 
			
		||||
        }
 | 
			
		||||
        return this.getVo(notification);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 分页查询消息通知列表
 | 
			
		||||
     *
 | 
			
		||||
     * @param req       查询条件
 | 
			
		||||
     * @param pageQuery 分页参数
 | 
			
		||||
     * @return 消息通知分页列表
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public TableDataInfo<MsgNotificationVo> queryPageList(MsgNotificationQueryReq req, PageQuery pageQuery) {
 | 
			
		||||
        Page<MsgNotification> result = this.page(pageQuery.build(), this.buildQueryWrapper(req));
 | 
			
		||||
        return TableDataInfo.build(this.getVoPage(result));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 查询符合条件的消息通知列表
 | 
			
		||||
     *
 | 
			
		||||
     * @param req 查询条件
 | 
			
		||||
     * @return 消息通知列表
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<MsgNotificationVo> queryList(MsgNotificationQueryReq req) {
 | 
			
		||||
        List<MsgNotification> list = this.list(this.buildQueryWrapper(req));
 | 
			
		||||
        // 获取发送用户信息
 | 
			
		||||
        List<Long> senderUserIds = list.stream()
 | 
			
		||||
            .map(MsgNotification::getSenderId).distinct().filter(id -> id != null && id != 0).toList();
 | 
			
		||||
        List<SysUserVo> senderUserVoList = userService.selectUserByIds(senderUserIds, null);
 | 
			
		||||
        Map<Long, String> senderUserMap = senderUserVoList.stream()
 | 
			
		||||
            .collect(Collectors.toMap(SysUserVo::getUserId, SysUserVo::getNickName));
 | 
			
		||||
        return list.stream().map(notification -> {
 | 
			
		||||
                MsgNotificationVo notificationVo = new MsgNotificationVo();
 | 
			
		||||
                BeanUtils.copyProperties(notification, notificationVo);
 | 
			
		||||
                // 关联发送用户信息
 | 
			
		||||
                Long senderId = notification.getSenderId();
 | 
			
		||||
                if (senderId != null && senderId != 0 && senderUserMap.containsKey(senderId)) {
 | 
			
		||||
                    notificationVo.setSenderName(senderUserMap.get(senderId));
 | 
			
		||||
                }
 | 
			
		||||
                return notificationVo;
 | 
			
		||||
            }
 | 
			
		||||
        ).toList();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 发送消息通知
 | 
			
		||||
     *
 | 
			
		||||
     * @param req 消息通知
 | 
			
		||||
     * @return 是否发送成功
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    @Transactional(rollbackFor = Exception.class)
 | 
			
		||||
    public Boolean sendMessage(MsgNotificationSendMessageReq req) {
 | 
			
		||||
        // 记录发送消息
 | 
			
		||||
        MsgNotification notification = new MsgNotification();
 | 
			
		||||
        BeanUtils.copyProperties(req, notification);
 | 
			
		||||
        Long recipientId = req.getRecipientId();
 | 
			
		||||
        if (userService.selectUserById(recipientId) == null) {
 | 
			
		||||
            throw new ServiceException("接收用户不存在", HttpStatus.NOT_FOUND);
 | 
			
		||||
        }
 | 
			
		||||
        Long typeId = notification.getTypeId();
 | 
			
		||||
        MsgTypeConfig typeConfig = typeConfigService.getById(typeId);
 | 
			
		||||
        if (typeConfig == null) {
 | 
			
		||||
            throw new ServiceException("消息类型不存在", HttpStatus.NOT_FOUND);
 | 
			
		||||
        }
 | 
			
		||||
        // 填充默认值
 | 
			
		||||
        Long userId = LoginHelper.getUserId();
 | 
			
		||||
        if (userId == null) {
 | 
			
		||||
            throw new ServiceException("未获取到用户信息", HttpStatus.UNAUTHORIZED);
 | 
			
		||||
        }
 | 
			
		||||
        notification.setSenderId(userId);
 | 
			
		||||
        boolean save = this.save(notification);
 | 
			
		||||
        if (!save) {
 | 
			
		||||
            throw new ServiceException("发送消息失败", HttpStatus.ERROR);
 | 
			
		||||
        }
 | 
			
		||||
        // 使用 sse 发送消息
 | 
			
		||||
        SseMessageDto sseMessageDto = new SseMessageDto();
 | 
			
		||||
        sseMessageDto.setUserIds(List.of(recipientId));
 | 
			
		||||
        String message = StringUtils.format("您有一条{}消息,请及时查看", typeConfig.getTypeName());
 | 
			
		||||
        sseMessageDto.setMessage(message);
 | 
			
		||||
        SseMessageUtils.publishMessage(sseMessageDto);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 批量删除消息通知信息
 | 
			
		||||
     *
 | 
			
		||||
     * @param ids 待删除的主键集合
 | 
			
		||||
     * @return 是否删除成功
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    @Transactional(rollbackFor = Exception.class)
 | 
			
		||||
    public Boolean deleteByIds(Collection<Long> ids) {
 | 
			
		||||
        List<MsgNotification> notifications = this.listByIds(ids);
 | 
			
		||||
        if (CollUtil.isEmpty(notifications)) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        Long userId = LoginHelper.getUserId();
 | 
			
		||||
        notifications.forEach(notification -> validHasPermission(userId, notification));
 | 
			
		||||
        return removeBatchByIds(ids);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取消息通知视图对象
 | 
			
		||||
     *
 | 
			
		||||
     * @param notification 消息通知对象
 | 
			
		||||
     * @return 消息通知视图对象
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public MsgNotificationVo getVo(MsgNotification notification) {
 | 
			
		||||
        MsgNotificationVo vo = new MsgNotificationVo();
 | 
			
		||||
        if (notification == null) {
 | 
			
		||||
            return vo;
 | 
			
		||||
        }
 | 
			
		||||
        BeanUtils.copyProperties(notification, vo);
 | 
			
		||||
        // 获取发送用户信息
 | 
			
		||||
        Long senderId = notification.getSenderId();
 | 
			
		||||
        if (senderId != null && senderId != 0) {
 | 
			
		||||
            SysUserVo userVo = userService.selectUserById(senderId);
 | 
			
		||||
            vo.setSenderName(userVo.getNickName());
 | 
			
		||||
        }
 | 
			
		||||
        return vo;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取消息通知查询条件封装
 | 
			
		||||
     *
 | 
			
		||||
     * @param req 查询条件
 | 
			
		||||
     * @return 查询条件封装
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public LambdaQueryWrapper<MsgNotification> buildQueryWrapper(MsgNotificationQueryReq req) {
 | 
			
		||||
        LambdaQueryWrapper<MsgNotification> lqw = new LambdaQueryWrapper<>();
 | 
			
		||||
        if (req == null) {
 | 
			
		||||
            return lqw;
 | 
			
		||||
        }
 | 
			
		||||
        Long projectId = req.getProjectId();
 | 
			
		||||
        Long recipientId = req.getRecipientId();
 | 
			
		||||
        Long senderId = req.getSenderId();
 | 
			
		||||
        Long typeId = req.getTypeId();
 | 
			
		||||
        String title = req.getTitle();
 | 
			
		||||
        String viewStatus = req.getViewStatus();
 | 
			
		||||
        lqw.eq(ObjectUtils.isNotEmpty(projectId), MsgNotification::getProjectId, projectId);
 | 
			
		||||
        lqw.eq(ObjectUtils.isNotEmpty(recipientId), MsgNotification::getRecipientId, recipientId);
 | 
			
		||||
        lqw.eq(ObjectUtils.isNotEmpty(senderId), MsgNotification::getSenderId, senderId);
 | 
			
		||||
        lqw.eq(ObjectUtils.isNotEmpty(typeId), MsgNotification::getTypeId, typeId);
 | 
			
		||||
        lqw.like(StringUtils.isNotBlank(title), MsgNotification::getTitle, title);
 | 
			
		||||
        lqw.eq(StringUtils.isNotBlank(viewStatus), MsgNotification::getViewStatus, viewStatus);
 | 
			
		||||
        return lqw;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取消息通知分页对象视图
 | 
			
		||||
     *
 | 
			
		||||
     * @param notificationPage 消息通知分页对象
 | 
			
		||||
     * @return 消息通知分页详情对象视图
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public Page<MsgNotificationVo> getVoPage(Page<MsgNotification> notificationPage) {
 | 
			
		||||
        List<MsgNotification> notificationList = notificationPage.getRecords();
 | 
			
		||||
        Page<MsgNotificationVo> notificationVoPage = new Page<>(
 | 
			
		||||
            notificationPage.getCurrent(),
 | 
			
		||||
            notificationPage.getSize(),
 | 
			
		||||
            notificationPage.getTotal());
 | 
			
		||||
        if (CollUtil.isEmpty(notificationList)) {
 | 
			
		||||
            return notificationVoPage;
 | 
			
		||||
        }
 | 
			
		||||
        // 获取发送用户信息
 | 
			
		||||
        List<Long> senderUserIds = notificationList.stream()
 | 
			
		||||
            .map(MsgNotification::getSenderId).distinct().filter(id -> id != null && id != 0).toList();
 | 
			
		||||
        List<SysUserVo> senderUserVoList = userService.selectUserByIds(senderUserIds, null);
 | 
			
		||||
        Map<Long, String> senderUserMap = senderUserVoList.stream()
 | 
			
		||||
            .collect(Collectors.toMap(SysUserVo::getUserId, SysUserVo::getNickName));
 | 
			
		||||
        List<MsgNotificationVo> notificationVoList = notificationList.stream().map(notification -> {
 | 
			
		||||
            MsgNotificationVo notificationVo = new MsgNotificationVo();
 | 
			
		||||
            BeanUtils.copyProperties(notification, notificationVo);
 | 
			
		||||
            // 关联发送用户信息
 | 
			
		||||
            Long senderId = notification.getSenderId();
 | 
			
		||||
            if (senderId != null && senderId != 0 && senderUserMap.containsKey(senderId)) {
 | 
			
		||||
                notificationVo.setSenderName(senderUserMap.get(senderId));
 | 
			
		||||
            }
 | 
			
		||||
            return notificationVo;
 | 
			
		||||
        }).toList();
 | 
			
		||||
        notificationVoPage.setRecords(notificationVoList);
 | 
			
		||||
        return notificationVoPage;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,166 @@
 | 
			
		||||
package org.dromara.message.service.impl;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.collection.CollUtil;
 | 
			
		||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 | 
			
		||||
import jakarta.annotation.Resource;
 | 
			
		||||
import org.dromara.common.mybatis.core.page.PageQuery;
 | 
			
		||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
 | 
			
		||||
import org.dromara.message.domain.MsgNotifyTargetDetail;
 | 
			
		||||
import org.dromara.message.domain.enums.MsgMessageTargetType;
 | 
			
		||||
import org.dromara.message.domain.vo.notifytargetdetail.MsgNotifyTargetDetailVo;
 | 
			
		||||
import org.dromara.message.mapper.MsgNotifyTargetDetailMapper;
 | 
			
		||||
import org.dromara.message.service.IMsgNotifyTargetDetailService;
 | 
			
		||||
import org.dromara.system.domain.bo.SysUserBo;
 | 
			
		||||
import org.dromara.system.domain.vo.SysDeptVo;
 | 
			
		||||
import org.dromara.system.domain.vo.SysRoleVo;
 | 
			
		||||
import org.dromara.system.domain.vo.SysUserVo;
 | 
			
		||||
import org.dromara.system.service.ISysDeptService;
 | 
			
		||||
import org.dromara.system.service.ISysRoleService;
 | 
			
		||||
import org.dromara.system.service.ISysUserService;
 | 
			
		||||
import org.springframework.beans.BeanUtils;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 通知人员配置详情Service业务层处理
 | 
			
		||||
 *
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05
 | 
			
		||||
 */
 | 
			
		||||
@Service
 | 
			
		||||
public class MsgNotifyTargetDetailServiceImpl extends ServiceImpl<MsgNotifyTargetDetailMapper, MsgNotifyTargetDetail>
 | 
			
		||||
    implements IMsgNotifyTargetDetailService {
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private ISysUserService userService;
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private ISysRoleService roleService;
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private ISysDeptService deptService;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 根据通知目标ID查询用户ID列表
 | 
			
		||||
     *
 | 
			
		||||
     * @param targetId 通知目标ID
 | 
			
		||||
     * @return 用户ID列表
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<Long> queryUserIdsByTargetId(Long targetId) {
 | 
			
		||||
        List<MsgNotifyTargetDetail> details = this.lambdaQuery()
 | 
			
		||||
            .eq(MsgNotifyTargetDetail::getTargetId, targetId)
 | 
			
		||||
            .list();
 | 
			
		||||
        List<Long> userIds = new ArrayList<>();
 | 
			
		||||
        details.forEach(detail -> {
 | 
			
		||||
            String targetType = detail.getTargetType();
 | 
			
		||||
            if (targetType.equals(MsgMessageTargetType.USER.getValue())) {
 | 
			
		||||
                userIds.add(detail.getTargetId());
 | 
			
		||||
            } else if (targetType.equals(MsgMessageTargetType.ROLE.getValue())) {
 | 
			
		||||
                SysUserBo userBo = new SysUserBo();
 | 
			
		||||
                userBo.setRoleId(detail.getTargetId());
 | 
			
		||||
                TableDataInfo<SysUserVo> dataInfo = userService.selectAllocatedList(userBo, new PageQuery(PageQuery.DEFAULT_PAGE_NUM, PageQuery.DEFAULT_PAGE_SIZE));
 | 
			
		||||
                List<SysUserVo> rows = dataInfo.getRows();
 | 
			
		||||
                List<Long> userIdList = rows.stream().map(SysUserVo::getUserId).distinct().filter(Objects::nonNull).toList();
 | 
			
		||||
                userIds.addAll(userIdList);
 | 
			
		||||
            } else if (targetType.equals(MsgMessageTargetType.DEPT.getValue())) {
 | 
			
		||||
                List<SysUserVo> userVos = userService.selectUserListByDept(detail.getTargetId());
 | 
			
		||||
                List<Long> userIdList = userVos.stream().map(SysUserVo::getUserId).distinct().filter(Objects::nonNull).toList();
 | 
			
		||||
                userIds.addAll(userIdList);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        return userIds;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 根据通知目标ID查询通知目标详情列表
 | 
			
		||||
     *
 | 
			
		||||
     * @param targetId 通知目标ID
 | 
			
		||||
     * @return 通知目标详情列表
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<MsgNotifyTargetDetailVo> queryVoListByTargetId(Long targetId) {
 | 
			
		||||
        List<MsgNotifyTargetDetail> details = this.lambdaQuery()
 | 
			
		||||
            .eq(MsgNotifyTargetDetail::getTargetId, targetId)
 | 
			
		||||
            .list();
 | 
			
		||||
        return this.getVoList(details);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取通知人员配置详情封装
 | 
			
		||||
     *
 | 
			
		||||
     * @param detail 通知人员配置详情
 | 
			
		||||
     * @return 通知人员配置详情封装
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public MsgNotifyTargetDetailVo getVo(MsgNotifyTargetDetail detail) {
 | 
			
		||||
        MsgNotifyTargetDetailVo vo = new MsgNotifyTargetDetailVo();
 | 
			
		||||
        if (detail == null) {
 | 
			
		||||
            return vo;
 | 
			
		||||
        }
 | 
			
		||||
        BeanUtils.copyProperties(detail, vo);
 | 
			
		||||
        Long targetId = detail.getTargetId();
 | 
			
		||||
        if (detail.getTargetType().equals(MsgMessageTargetType.USER.getValue())) {
 | 
			
		||||
            vo.setTargetName(userService.selectUserById(targetId).getUserName());
 | 
			
		||||
        } else if (detail.getTargetType().equals(MsgMessageTargetType.ROLE.getValue())) {
 | 
			
		||||
            vo.setTargetName(roleService.selectRoleById(targetId).getRoleName());
 | 
			
		||||
        } else if (detail.getTargetType().equals(MsgMessageTargetType.DEPT.getValue())) {
 | 
			
		||||
            vo.setTargetName(deptService.selectDeptById(targetId).getDeptName());
 | 
			
		||||
        }
 | 
			
		||||
        return vo;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 批量获取通知人员配置详情封装
 | 
			
		||||
     *
 | 
			
		||||
     * @param detailList 通知人员配置详情列表
 | 
			
		||||
     * @return 通知人员配置详情封装列表
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<MsgNotifyTargetDetailVo> getVoList(List<MsgNotifyTargetDetail> detailList) {
 | 
			
		||||
        if (CollUtil.isEmpty(detailList)) {
 | 
			
		||||
            return List.of();
 | 
			
		||||
        }
 | 
			
		||||
        // 获取用户列表
 | 
			
		||||
        List<Long> userIds = new ArrayList<>();
 | 
			
		||||
        List<Long> roleIds = new ArrayList<>();
 | 
			
		||||
        List<Long> deptIds = new ArrayList<>();
 | 
			
		||||
        detailList.forEach(detail -> {
 | 
			
		||||
            String targetType = detail.getTargetType();
 | 
			
		||||
            Long targetId = detail.getTargetId();
 | 
			
		||||
            if (targetType.equals(MsgMessageTargetType.USER.getValue())) {
 | 
			
		||||
                userIds.add(targetId);
 | 
			
		||||
            } else if (targetType.equals(MsgMessageTargetType.ROLE.getValue())) {
 | 
			
		||||
                roleIds.add(targetId);
 | 
			
		||||
            } else if (targetType.equals(MsgMessageTargetType.DEPT.getValue())) {
 | 
			
		||||
                deptIds.add(targetId);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        List<Long> newUserIds = userIds.stream().distinct().filter(Objects::nonNull).toList();
 | 
			
		||||
        List<Long> newRoleIds = roleIds.stream().distinct().filter(Objects::nonNull).toList();
 | 
			
		||||
        List<Long> newDeptIds = deptIds.stream().distinct().filter(Objects::nonNull).toList();
 | 
			
		||||
        List<SysUserVo> userVos = userService.selectUserByIds(newUserIds, null);
 | 
			
		||||
        List<SysRoleVo> roleVos = roleService.selectRoleByIds(newRoleIds);
 | 
			
		||||
        List<SysDeptVo> deptVos = deptService.selectDeptByIds(newDeptIds);
 | 
			
		||||
        Map<Long, String> userMap = userVos.stream().collect(Collectors.toMap(SysUserVo::getUserId, SysUserVo::getNickName));
 | 
			
		||||
        Map<Long, String> roleMap = roleVos.stream().collect(Collectors.toMap(SysRoleVo::getRoleId, SysRoleVo::getRoleName));
 | 
			
		||||
        Map<Long, String> deptMap = deptVos.stream().collect(Collectors.toMap(SysDeptVo::getDeptId, SysDeptVo::getDeptName));
 | 
			
		||||
        return detailList.stream().map(detail -> {
 | 
			
		||||
            MsgNotifyTargetDetailVo vo = new MsgNotifyTargetDetailVo();
 | 
			
		||||
            BeanUtils.copyProperties(detail, vo);
 | 
			
		||||
            if (detail.getTargetType().equals(MsgMessageTargetType.USER.getValue())) {
 | 
			
		||||
                vo.setTargetName(userMap.get(detail.getTargetId()));
 | 
			
		||||
            } else if (detail.getTargetType().equals(MsgMessageTargetType.ROLE.getValue())) {
 | 
			
		||||
                vo.setTargetName(roleMap.get(detail.getTargetId()));
 | 
			
		||||
            } else if (detail.getTargetType().equals(MsgMessageTargetType.DEPT.getValue())) {
 | 
			
		||||
                vo.setTargetName(deptMap.get(detail.getTargetId()));
 | 
			
		||||
            }
 | 
			
		||||
            return vo;
 | 
			
		||||
        }).toList();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,268 @@
 | 
			
		||||
package org.dromara.message.service.impl;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.collection.CollUtil;
 | 
			
		||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 | 
			
		||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 | 
			
		||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 | 
			
		||||
import jakarta.annotation.Resource;
 | 
			
		||||
import org.dromara.common.core.constant.HttpStatus;
 | 
			
		||||
import org.dromara.common.core.exception.ServiceException;
 | 
			
		||||
import org.dromara.common.core.utils.ObjectUtils;
 | 
			
		||||
import org.dromara.common.core.utils.StringUtils;
 | 
			
		||||
import org.dromara.common.mybatis.core.page.PageQuery;
 | 
			
		||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
 | 
			
		||||
import org.dromara.message.domain.MsgNotifyTarget;
 | 
			
		||||
import org.dromara.message.domain.MsgNotifyTargetDetail;
 | 
			
		||||
import org.dromara.message.domain.dto.notifytarget.MsgNotifyTargetCreateReq;
 | 
			
		||||
import org.dromara.message.domain.dto.notifytarget.MsgNotifyTargetQueryReq;
 | 
			
		||||
import org.dromara.message.domain.dto.notifytarget.MsgNotifyTargetUpdateReq;
 | 
			
		||||
import org.dromara.message.domain.dto.notifytargetdetail.MsgNotifyTargetDetailCreateDto;
 | 
			
		||||
import org.dromara.message.domain.dto.notifytargetdetail.MsgNotifyTargetDetailUpdateDto;
 | 
			
		||||
import org.dromara.message.domain.vo.notifytarget.MsgNotifyTargetVo;
 | 
			
		||||
import org.dromara.message.domain.vo.notifytargetdetail.MsgNotifyTargetDetailVo;
 | 
			
		||||
import org.dromara.message.mapper.MsgNotifyTargetMapper;
 | 
			
		||||
import org.dromara.message.service.IMsgNotifyTargetDetailService;
 | 
			
		||||
import org.dromara.message.service.IMsgNotifyTargetService;
 | 
			
		||||
import org.springframework.beans.BeanUtils;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
import org.springframework.transaction.annotation.Transactional;
 | 
			
		||||
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 通知人员配置Service业务层处理
 | 
			
		||||
 *
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05
 | 
			
		||||
 */
 | 
			
		||||
@Service
 | 
			
		||||
public class MsgNotifyTargetServiceImpl extends ServiceImpl<MsgNotifyTargetMapper, MsgNotifyTarget>
 | 
			
		||||
    implements IMsgNotifyTargetService {
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private IMsgNotifyTargetDetailService notifyTargetDetailService;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 查询通知人员配置
 | 
			
		||||
     *
 | 
			
		||||
     * @param id 主键
 | 
			
		||||
     * @return 通知人员配置
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public MsgNotifyTargetVo queryById(Long id) {
 | 
			
		||||
        MsgNotifyTarget notifyTarget = this.getById(id);
 | 
			
		||||
        if (notifyTarget == null) {
 | 
			
		||||
            throw new ServiceException("通知人员配置信息不存在", HttpStatus.NOT_FOUND);
 | 
			
		||||
        }
 | 
			
		||||
        return this.getVo(notifyTarget);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 分页查询通知人员配置列表
 | 
			
		||||
     *
 | 
			
		||||
     * @param req       查询条件
 | 
			
		||||
     * @param pageQuery 分页参数
 | 
			
		||||
     * @return 通知人员配置分页列表
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public TableDataInfo<MsgNotifyTargetVo> queryPageList(MsgNotifyTargetQueryReq req, PageQuery pageQuery) {
 | 
			
		||||
        Page<MsgNotifyTarget> result = this.page(pageQuery.build(), this.buildQueryWrapper(req));
 | 
			
		||||
        return TableDataInfo.build(this.getVoPage(result));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 查询符合条件的通知人员配置列表
 | 
			
		||||
     *
 | 
			
		||||
     * @param req 查询条件
 | 
			
		||||
     * @return 通知人员配置列表
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<MsgNotifyTargetVo> queryList(MsgNotifyTargetQueryReq req) {
 | 
			
		||||
        return this.list(this.buildQueryWrapper(req)).stream().map(this::getVo).toList();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 新增通知人员配置
 | 
			
		||||
     *
 | 
			
		||||
     * @param req 通知人员配置
 | 
			
		||||
     * @return 是否新增成功
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    @Transactional(rollbackFor = Exception.class)
 | 
			
		||||
    public Boolean insertByBo(MsgNotifyTargetCreateReq req) {
 | 
			
		||||
        MsgNotifyTarget target = new MsgNotifyTarget();
 | 
			
		||||
        BeanUtils.copyProperties(req, target);
 | 
			
		||||
        boolean save = this.save(target);
 | 
			
		||||
        if (!save) {
 | 
			
		||||
            throw new ServiceException("新增通知人员配置信息异常", HttpStatus.ERROR);
 | 
			
		||||
        }
 | 
			
		||||
        List<MsgNotifyTargetDetailCreateDto> detailList = req.getDetailList();
 | 
			
		||||
        List<MsgNotifyTargetDetail> saveDetail = detailList.stream().map(detail -> {
 | 
			
		||||
            MsgNotifyTargetDetail entity = new MsgNotifyTargetDetail();
 | 
			
		||||
            entity.setConfigId(target.getId());
 | 
			
		||||
            entity.setTargetId(detail.getTargetId());
 | 
			
		||||
            entity.setTargetType(detail.getTargetType());
 | 
			
		||||
            return entity;
 | 
			
		||||
        }).toList();
 | 
			
		||||
        boolean b = notifyTargetDetailService.saveBatch(saveDetail);
 | 
			
		||||
        if (!b) {
 | 
			
		||||
            throw new ServiceException("新增通知人员配置信息异常", HttpStatus.ERROR);
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 修改通知人员配置
 | 
			
		||||
     *
 | 
			
		||||
     * @param req 通知人员配置
 | 
			
		||||
     * @return 是否修改成功
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    @Transactional(rollbackFor = Exception.class)
 | 
			
		||||
    public Boolean updateByBo(MsgNotifyTargetUpdateReq req) {
 | 
			
		||||
        Long id = req.getId();
 | 
			
		||||
        MsgNotifyTarget notifyTarget = this.getById(id);
 | 
			
		||||
        if (notifyTarget == null) {
 | 
			
		||||
            throw new ServiceException("修改通知人员配置信息不存在", HttpStatus.ERROR);
 | 
			
		||||
        }
 | 
			
		||||
        MsgNotifyTarget target = new MsgNotifyTarget();
 | 
			
		||||
        BeanUtils.copyProperties(req, target);
 | 
			
		||||
        List<MsgNotifyTargetDetailUpdateDto> detailList = req.getDetailList();
 | 
			
		||||
        // 判断是否需要新增或删除配置详情
 | 
			
		||||
        if (CollUtil.isNotEmpty(detailList)) {
 | 
			
		||||
            // 1. 从数据库中获取当前配置下的所有旧详情
 | 
			
		||||
            List<MsgNotifyTargetDetail> oldDetails = notifyTargetDetailService.lambdaQuery()
 | 
			
		||||
                .eq(MsgNotifyTargetDetail::getTargetId, id)
 | 
			
		||||
                .list();
 | 
			
		||||
            // 2. 计算需要删除的详情ID
 | 
			
		||||
            // 提取前端提交的详情中,所有已存在的记录ID (ID不为null)
 | 
			
		||||
            Set<Long> incomingIds = detailList.stream()
 | 
			
		||||
                .map(MsgNotifyTargetDetailUpdateDto::getId)
 | 
			
		||||
                .filter(Objects::nonNull)
 | 
			
		||||
                .collect(Collectors.toSet());
 | 
			
		||||
 | 
			
		||||
            // 筛选出 oldDetails 中 ID 不在 incomingIds 里的记录,这些就是要删除的
 | 
			
		||||
            List<Long> idsToDelete = oldDetails.stream()
 | 
			
		||||
                .map(MsgNotifyTargetDetail::getId)
 | 
			
		||||
                .filter(detailId -> !incomingIds.contains(detailId))
 | 
			
		||||
                .toList();
 | 
			
		||||
 | 
			
		||||
            // 3. 执行删除操作
 | 
			
		||||
            if (CollUtil.isNotEmpty(idsToDelete)) {
 | 
			
		||||
                notifyTargetDetailService.removeBatchByIds(idsToDelete);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // 4. 准备新增和修改的数据,并执行批量保存或更新
 | 
			
		||||
            if (CollUtil.isNotEmpty(detailList)) {
 | 
			
		||||
                // 将 DTO 列表转换为实体列表
 | 
			
		||||
                List<MsgNotifyTargetDetail> entitiesToSaveOrUpdate = detailList.stream().map(dto -> {
 | 
			
		||||
                    MsgNotifyTargetDetail entity = new MsgNotifyTargetDetail();
 | 
			
		||||
                    entity.setId(dto.getId()); // ID为null是新增,不为null是更新
 | 
			
		||||
                    entity.setConfigId(id); // 设置关联的父ID
 | 
			
		||||
                    entity.setTargetType(dto.getTargetType());
 | 
			
		||||
                    entity.setTargetId(dto.getTargetId());
 | 
			
		||||
                    return entity;
 | 
			
		||||
                }).collect(Collectors.toList());
 | 
			
		||||
 | 
			
		||||
                // 5. 执行批量新增或更新
 | 
			
		||||
                notifyTargetDetailService.saveOrUpdateBatch(entitiesToSaveOrUpdate);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        boolean b = this.updateById(target);
 | 
			
		||||
        if (!b) {
 | 
			
		||||
            throw new ServiceException("修改通知人员配置失败", HttpStatus.ERROR);
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 批量删除通知人员配置信息
 | 
			
		||||
     *
 | 
			
		||||
     * @param ids 待删除的主键集合
 | 
			
		||||
     * @return 是否删除成功
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    @Transactional(rollbackFor = Exception.class)
 | 
			
		||||
    public Boolean deleteByIds(Collection<Long> ids) {
 | 
			
		||||
        List<MsgNotifyTargetDetail> details = notifyTargetDetailService.lambdaQuery()
 | 
			
		||||
            .in(MsgNotifyTargetDetail::getTargetId, ids)
 | 
			
		||||
            .list();
 | 
			
		||||
        boolean result = notifyTargetDetailService.removeBatchByIds(details);
 | 
			
		||||
        if (!result) {
 | 
			
		||||
            throw new ServiceException("删除通知人员配置详情信息失败");
 | 
			
		||||
        }
 | 
			
		||||
        result = this.removeBatchByIds(ids);
 | 
			
		||||
        if (!result) {
 | 
			
		||||
            throw new ServiceException("删除通知人员配置信息失败");
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取通知人员配置视图对象
 | 
			
		||||
     *
 | 
			
		||||
     * @param notifyTarget 通知人员配置对象
 | 
			
		||||
     * @return 通知人员配置视图对象
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public MsgNotifyTargetVo getVo(MsgNotifyTarget notifyTarget) {
 | 
			
		||||
        MsgNotifyTargetVo vo = new MsgNotifyTargetVo();
 | 
			
		||||
        if (notifyTarget == null) {
 | 
			
		||||
            return vo;
 | 
			
		||||
        }
 | 
			
		||||
        BeanUtils.copyProperties(notifyTarget, vo);
 | 
			
		||||
        Long id = notifyTarget.getId();
 | 
			
		||||
        List<MsgNotifyTargetDetailVo> detailVos = notifyTargetDetailService.queryVoListByTargetId(id);
 | 
			
		||||
        vo.setDetailList(detailVos);
 | 
			
		||||
        return vo;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取通知人员配置查询条件封装
 | 
			
		||||
     *
 | 
			
		||||
     * @param req 查询条件
 | 
			
		||||
     * @return 查询条件封装
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public LambdaQueryWrapper<MsgNotifyTarget> buildQueryWrapper(MsgNotifyTargetQueryReq req) {
 | 
			
		||||
        LambdaQueryWrapper<MsgNotifyTarget> lqw = new LambdaQueryWrapper<>();
 | 
			
		||||
        if (req == null) {
 | 
			
		||||
            return lqw;
 | 
			
		||||
        }
 | 
			
		||||
        Long projectId = req.getProjectId();
 | 
			
		||||
        Long typeId = req.getTypeId();
 | 
			
		||||
        String status = req.getStatus();
 | 
			
		||||
        lqw.eq(ObjectUtils.isNotEmpty(projectId), MsgNotifyTarget::getProjectId, projectId);
 | 
			
		||||
        lqw.eq(ObjectUtils.isNotEmpty(typeId), MsgNotifyTarget::getTypeId, typeId);
 | 
			
		||||
        lqw.eq(StringUtils.isNotBlank(status), MsgNotifyTarget::getStatus, status);
 | 
			
		||||
        return lqw;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取通知人员配置分页对象视图
 | 
			
		||||
     *
 | 
			
		||||
     * @param notifyTargetPage 通知人员配置分页对象
 | 
			
		||||
     * @return 通知人员配置分页详情对象视图
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public Page<MsgNotifyTargetVo> getVoPage(Page<MsgNotifyTarget> notifyTargetPage) {
 | 
			
		||||
        List<MsgNotifyTarget> notifyTargetList = notifyTargetPage.getRecords();
 | 
			
		||||
        Page<MsgNotifyTargetVo> voPage = new Page<>(
 | 
			
		||||
            notifyTargetPage.getCurrent(),
 | 
			
		||||
            notifyTargetPage.getSize(),
 | 
			
		||||
            notifyTargetPage.getTotal()
 | 
			
		||||
        );
 | 
			
		||||
        List<MsgNotifyTargetVo> targetVoList = notifyTargetList.stream().map(notifyTarget -> {
 | 
			
		||||
            MsgNotifyTargetVo vo = new MsgNotifyTargetVo();
 | 
			
		||||
            BeanUtils.copyProperties(notifyTarget, vo);
 | 
			
		||||
            vo.setDetailList(notifyTargetDetailService.queryVoListByTargetId(notifyTarget.getId()));
 | 
			
		||||
            return vo;
 | 
			
		||||
        }).toList();
 | 
			
		||||
        voPage.setRecords(targetVoList);
 | 
			
		||||
        return voPage;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,180 @@
 | 
			
		||||
package org.dromara.message.service.impl;
 | 
			
		||||
 | 
			
		||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 | 
			
		||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 | 
			
		||||
import org.dromara.common.core.constant.HttpStatus;
 | 
			
		||||
import org.dromara.common.core.exception.ServiceException;
 | 
			
		||||
import org.dromara.common.core.utils.ObjectUtils;
 | 
			
		||||
import org.dromara.common.core.utils.StringUtils;
 | 
			
		||||
import org.dromara.message.domain.MsgTypeConfig;
 | 
			
		||||
import org.dromara.message.domain.dto.typeconfig.MsgTypeConfigCreateReq;
 | 
			
		||||
import org.dromara.message.domain.dto.typeconfig.MsgTypeConfigQueryReq;
 | 
			
		||||
import org.dromara.message.domain.dto.typeconfig.MsgTypeConfigUpdateReq;
 | 
			
		||||
import org.dromara.message.domain.vo.typeconfig.MsgTypeConfigVo;
 | 
			
		||||
import org.dromara.message.mapper.MsgTypeConfigMapper;
 | 
			
		||||
import org.dromara.message.service.IMsgTypeConfigService;
 | 
			
		||||
import org.springframework.beans.BeanUtils;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
import org.springframework.transaction.annotation.Transactional;
 | 
			
		||||
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 消息类型配置Service业务层处理
 | 
			
		||||
 *
 | 
			
		||||
 * @author lilemy
 | 
			
		||||
 * @date 2025-08-05
 | 
			
		||||
 */
 | 
			
		||||
@Service
 | 
			
		||||
public class MsgTypeConfigServiceImpl extends ServiceImpl<MsgTypeConfigMapper, MsgTypeConfig>
 | 
			
		||||
    implements IMsgTypeConfigService {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 查询消息类型配置
 | 
			
		||||
     *
 | 
			
		||||
     * @param id 主键
 | 
			
		||||
     * @return 消息类型配置
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public MsgTypeConfigVo queryById(Long id) {
 | 
			
		||||
        MsgTypeConfig typeConfig = this.getById(id);
 | 
			
		||||
        if (typeConfig == null) {
 | 
			
		||||
            throw new ServiceException("消息类型配置信息不存在", HttpStatus.NOT_FOUND);
 | 
			
		||||
        }
 | 
			
		||||
        return this.getVo(typeConfig);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 查询符合条件的消息类型配置列表
 | 
			
		||||
     *
 | 
			
		||||
     * @param req 查询条件
 | 
			
		||||
     * @return 消息类型配置列表
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<MsgTypeConfigVo> queryList(MsgTypeConfigQueryReq req) {
 | 
			
		||||
        List<MsgTypeConfig> result = this.list(this.buildQueryWrapper(req));
 | 
			
		||||
        return this.getVoList(result);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 新增消息类型配置
 | 
			
		||||
     *
 | 
			
		||||
     * @param req 消息类型配置
 | 
			
		||||
     * @return 新增成功消息类型配置id
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public Long insertByBo(MsgTypeConfigCreateReq req) {
 | 
			
		||||
        MsgTypeConfig typeConfig = new MsgTypeConfig();
 | 
			
		||||
        BeanUtils.copyProperties(req, typeConfig);
 | 
			
		||||
        // 校验编号是否重复
 | 
			
		||||
        boolean b = this.lambdaQuery()
 | 
			
		||||
            .eq(MsgTypeConfig::getTypeCode, typeConfig.getTypeCode())
 | 
			
		||||
            .in(MsgTypeConfig::getProjectId, typeConfig.getProjectId(), 0L)
 | 
			
		||||
            .count() > 0;
 | 
			
		||||
        if (b) {
 | 
			
		||||
            throw new ServiceException("当前消息编号已存在", HttpStatus.CONFLICT);
 | 
			
		||||
        }
 | 
			
		||||
        boolean save = this.save(typeConfig);
 | 
			
		||||
        if (!save) {
 | 
			
		||||
            throw new ServiceException("新增消息类型配置信息异常", HttpStatus.ERROR);
 | 
			
		||||
        }
 | 
			
		||||
        return typeConfig.getId();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 修改消息类型配置
 | 
			
		||||
     *
 | 
			
		||||
     * @param req 消息类型配置
 | 
			
		||||
     * @return 是否修改成功
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public Boolean updateByBo(MsgTypeConfigUpdateReq req) {
 | 
			
		||||
        Long id = req.getId();
 | 
			
		||||
        MsgTypeConfig oldTypeConfig = this.getById(id);
 | 
			
		||||
        if (oldTypeConfig == null) {
 | 
			
		||||
            throw new ServiceException("消息类型配置信息不存在", HttpStatus.NOT_FOUND);
 | 
			
		||||
        }
 | 
			
		||||
        MsgTypeConfig typeConfig = new MsgTypeConfig();
 | 
			
		||||
        BeanUtils.copyProperties(req, typeConfig);
 | 
			
		||||
        // 校验编号是否重复
 | 
			
		||||
        if (!typeConfig.getTypeCode().equals(oldTypeConfig.getTypeCode())){
 | 
			
		||||
            boolean b = this.lambdaQuery()
 | 
			
		||||
                .eq(MsgTypeConfig::getTypeCode, typeConfig.getTypeCode())
 | 
			
		||||
                .in(MsgTypeConfig::getProjectId, typeConfig.getProjectId(), 0L)
 | 
			
		||||
                .count() > 0;
 | 
			
		||||
                if (b) {
 | 
			
		||||
                    throw new ServiceException("当前消息编号已存在", HttpStatus.CONFLICT);
 | 
			
		||||
                }
 | 
			
		||||
        }
 | 
			
		||||
        boolean result = this.updateById(typeConfig);
 | 
			
		||||
        if (!result) {
 | 
			
		||||
            throw new ServiceException("修改消息类型配置信息异常", HttpStatus.ERROR);
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 批量删除消息类型配置信息
 | 
			
		||||
     *
 | 
			
		||||
     * @param ids 待删除的主键集合
 | 
			
		||||
     * @return 是否删除成功
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    @Transactional(rollbackFor = Exception.class)
 | 
			
		||||
    public Boolean deleteByIds(Collection<Long> ids) {
 | 
			
		||||
        return this.removeBatchByIds(ids);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取消息类型配置视图对象
 | 
			
		||||
     *
 | 
			
		||||
     * @param typeConfig 消息类型配置对象
 | 
			
		||||
     * @return 消息类型配置视图对象
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public MsgTypeConfigVo getVo(MsgTypeConfig typeConfig) {
 | 
			
		||||
        MsgTypeConfigVo vo = new MsgTypeConfigVo();
 | 
			
		||||
        if (typeConfig == null) {
 | 
			
		||||
            return vo;
 | 
			
		||||
        }
 | 
			
		||||
        BeanUtils.copyProperties(typeConfig, vo);
 | 
			
		||||
        return vo;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取消息类型配置查询条件封装
 | 
			
		||||
     *
 | 
			
		||||
     * @param req 查询条件
 | 
			
		||||
     * @return 查询条件封装
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public LambdaQueryWrapper<MsgTypeConfig> buildQueryWrapper(MsgTypeConfigQueryReq req) {
 | 
			
		||||
        LambdaQueryWrapper<MsgTypeConfig> lqw = new LambdaQueryWrapper<>();
 | 
			
		||||
        if (req == null) {
 | 
			
		||||
            return lqw;
 | 
			
		||||
        }
 | 
			
		||||
        Long projectId = req.getProjectId();
 | 
			
		||||
        Long parentId = req.getParentId();
 | 
			
		||||
        String typeCode = req.getTypeCode();
 | 
			
		||||
        String typeName = req.getTypeName();
 | 
			
		||||
        String status = req.getStatus();
 | 
			
		||||
        lqw.eq(ObjectUtils.isNotEmpty(projectId), MsgTypeConfig::getProjectId, projectId);
 | 
			
		||||
        lqw.eq(ObjectUtils.isNotEmpty(parentId), MsgTypeConfig::getParentId, parentId);
 | 
			
		||||
        lqw.eq(StringUtils.isNotBlank(typeCode), MsgTypeConfig::getTypeCode, typeCode);
 | 
			
		||||
        lqw.like(StringUtils.isNotBlank(typeName), MsgTypeConfig::getTypeName, typeName);
 | 
			
		||||
        lqw.eq(StringUtils.isNotBlank(status), MsgTypeConfig::getStatus, status);
 | 
			
		||||
        return lqw;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取消息类型配置分页对象视图
 | 
			
		||||
     *
 | 
			
		||||
     * @param typeConfigList 消息类型配置分页对象
 | 
			
		||||
     * @return 消息类型配置分页对象视图
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<MsgTypeConfigVo> getVoList(List<MsgTypeConfig> typeConfigList) {
 | 
			
		||||
        return typeConfigList.stream().map(this::getVo).toList();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,7 @@
 | 
			
		||||
<?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="org.dromara.message.mapper.MsgNotificationMapper">
 | 
			
		||||
 | 
			
		||||
</mapper>
 | 
			
		||||
@ -0,0 +1,7 @@
 | 
			
		||||
<?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="org.dromara.message.mapper.MsgNotifyTargetDetailMapper">
 | 
			
		||||
 | 
			
		||||
</mapper>
 | 
			
		||||
@ -0,0 +1,7 @@
 | 
			
		||||
<?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="org.dromara.message.mapper.MsgNotifyTargetMapper">
 | 
			
		||||
 | 
			
		||||
</mapper>
 | 
			
		||||
@ -0,0 +1,7 @@
 | 
			
		||||
<?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="org.dromara.message.mapper.MsgTypeConfigMapper">
 | 
			
		||||
 | 
			
		||||
</mapper>
 | 
			
		||||
		Reference in New Issue
	
	Block a user