diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/domain/BaseEntity.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/domain/BaseEntity.java
index 969ae6b5e..749fde7fe 100644
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/domain/BaseEntity.java
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/domain/BaseEntity.java
@@ -31,11 +31,11 @@ public class BaseEntity implements Serializable {
@TableField(exist = false)
private String searchValue;
- /**
- * 创建部门
- */
- @TableField(fill = FieldFill.INSERT)
- private Long createDept;
+// /**
+// * 创建部门
+// */
+// @TableField(fill = FieldFill.INSERT)
+// private Long createDept;
/**
* 创建者
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java
index 713d4ce0c..5413f6178 100644
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java
@@ -45,7 +45,7 @@ public class InjectionMetaObjectHandler implements MetaObjectHandler {
// 填充创建人、更新人和创建部门信息
baseEntity.setCreateBy(userId);
baseEntity.setUpdateBy(userId);
- baseEntity.setCreateDept(ObjectUtils.notNull(baseEntity.getCreateDept(), loginUser.getDeptId()));
+// baseEntity.setCreateDept(ObjectUtils.notNull(baseEntity.getCreateDept(), loginUser.getDeptId()));
}
}
} else {
diff --git a/ruoyi-modules/ruoyi-system/pom.xml b/ruoyi-modules/ruoyi-system/pom.xml
index 7fdea9248..dd960febd 100644
--- a/ruoyi-modules/ruoyi-system/pom.xml
+++ b/ruoyi-modules/ruoyi-system/pom.xml
@@ -20,6 +20,7 @@
org.dromara
ruoyi-common-core
+ ${revision}
@@ -112,6 +113,23 @@
fastjson
+
+
+ org.springframework.boot
+ spring-boot-starter-websocket
+
+
+
+
+ jakarta.websocket
+ jakarta.websocket-api
+
+
+
+
+ org.apache.tomcat.embed
+ tomcat-embed-websocket
+
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/SysMessageController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/SysMessageController.java
new file mode 100644
index 000000000..2e99b35e2
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/SysMessageController.java
@@ -0,0 +1,178 @@
+package org.dromara.system.controller;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.service.UserService;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.core.validate.QueryGroup;
+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.common.satoken.utils.LoginHelper;
+import org.dromara.system.domain.SysMessage;
+import org.dromara.system.domain.SysUser;
+import org.dromara.system.domain.bo.SysMessageBo;
+import org.dromara.system.domain.bo.SysUserBo;
+import org.dromara.system.domain.vo.SysMessageVo;
+import org.dromara.system.domain.vo.SysUserVo;
+import org.dromara.system.service.ISysMessageService;
+import org.dromara.system.service.ISysUserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.StringUtils;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 消息管理
+ *
+ * @author ruoyi
+ */
+@Validated
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/system/message")
+public class SysMessageController extends BaseController {
+
+ private final ISysMessageService messageService;
+ private final ISysUserService userService;
+
+ /**
+ * 获取当前用户ID
+ */
+ private Long getUserId() {
+ return LoginHelper.getUserId();
+ }
+
+ /**
+ * 查询消息列表
+ */
+ @SaCheckPermission("system:message:list")
+ @PostMapping("/list")
+ public R> list(@RequestBody SysMessageBo bo, @RequestBody Page page) {
+ Page messagePage = messageService.page(page, bo.toWrapper());
+ Page voPage = new Page<>(messagePage.getCurrent(), messagePage.getSize(), messagePage.getTotal());
+ voPage.setRecords(MapstructUtils.convert(messagePage.getRecords(), SysMessageVo.class));
+ return R.ok(voPage);
+ }
+
+ /**
+ * 获取消息详细信息
+ *
+ * @param id 消息ID
+ */
+ @SaCheckPermission("system:message:query")
+ @GetMapping("/{id}")
+ public R getInfo(@NotNull(message = "消息ID不能为空") @PathVariable Long id) {
+ return R.ok(messageService.selectMessageById(id));
+ }
+
+ /**
+ * 发送消息
+ */
+ @SaCheckPermission("system:message:send")
+ @Log(title = "消息管理", businessType = BusinessType.INSERT)
+ @RepeatSubmit()
+ @PostMapping("/send")
+ public R send(@Validated(AddGroup.class) @RequestBody SysMessageBo bo) {
+ List users = userService.selectUserListByDept(null);
+ List userIds;
+
+ switch (bo.getSendScope()) {
+ case "all":
+ // 全部用户
+ userIds = users.stream().map(SysUserVo::getUserId).toList();
+ break;
+ case "expert":
+ // 达人
+ userIds = users.stream()
+ .filter(user -> "expert".equals(user.getUserType()))
+ .map(SysUserVo::getUserId)
+ .toList();
+ break;
+ case "merchant":
+ // 商户
+ userIds = users.stream()
+ .filter(user -> "merchant".equals(user.getUserType()))
+ .map(SysUserVo::getUserId)
+ .toList();
+ break;
+ case "user":
+ // 普通用户
+ userIds = users.stream()
+ .filter(user -> "user".equals(user.getUserType()))
+ .map(SysUserVo::getUserId)
+ .toList();
+ break;
+ default:
+ // 其他情况(如指定userIds)
+ userIds = bo.getUserIds();
+ }
+
+ return toAjax(messageService.sendMessageToUsers(bo, userIds));
+ }
+
+ /**
+ * 标记消息为已读
+ */
+ @SaCheckPermission("system:message:mark")
+ @Log(title = "消息管理", businessType = BusinessType.UPDATE)
+ @PutMapping("/mark/{id}")
+ public R markAsRead(@NotNull(message = "消息ID不能为空") @PathVariable Long id) {
+ return toAjax(messageService.markAsRead(id, getUserId()));
+ }
+
+ /**
+ * 删除消息
+ *
+ * @param ids 消息ID串
+ */
+ @SaCheckPermission("system:message:remove")
+ @Log(title = "消息管理", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public R remove(@NotEmpty(message = "消息ID不能为空") @PathVariable Long[] ids) {
+ return toAjax(messageService.deleteMessageByIds(ids));
+ }
+
+ /**
+ * 获取未读消息列表
+ */
+ @SaCheckPermission("system:message:list")
+ @GetMapping("/unread")
+ public TableDataInfo unreadList(PageQuery pageQuery) {
+ return messageService.selectPageUnreadMessages(getUserId(), pageQuery);
+ }
+
+ /**
+ * 获取已读消息列表
+ */
+ @SaCheckPermission("system:message:list")
+ @GetMapping("/read")
+ public TableDataInfo readList(PageQuery pageQuery) {
+ return messageService.selectPageReadMessages(getUserId(), pageQuery);
+ }
+
+ /**
+ * 获取用户列表
+ */
+// @SaCheckPermission("system:message:list")
+// @GetMapping("/user/list")
+// public R> getUserList() {
+// PageQuery pageQuery = new PageQuery();
+// pageQuery.setPageNum(1);
+// pageQuery.setPageSize(Integer.MAX_VALUE);
+// TableDataInfo users = userService.selectPageUserList(new SysUserBo(), pageQuery);
+// return R.ok(users);
+// }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/SysMessageTemplateController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/SysMessageTemplateController.java
new file mode 100644
index 000000000..7ab52929a
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/SysMessageTemplateController.java
@@ -0,0 +1,90 @@
+package org.dromara.system.controller;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+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.system.domain.bo.SysMessageTemplateBo;
+import org.dromara.system.domain.vo.SysMessageTemplateVo;
+import org.dromara.system.service.ISysMessageTemplateService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 消息模板管理
+ *
+ * @author ruoyi
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/system/message/template")
+public class SysMessageTemplateController extends BaseController {
+
+ private final ISysMessageTemplateService templateService;
+
+ /**
+ * 查询消息模板列表
+ */
+ @SaCheckPermission("system:message:template:list")
+ @GetMapping("/list")
+ public TableDataInfo list(SysMessageTemplateBo bo, PageQuery pageQuery) {
+ return templateService.selectTemplatePage(bo, pageQuery);
+ }
+
+ /**
+ * 获取消息模板详细信息
+ *
+ * @param id 消息模板ID
+ */
+ @SaCheckPermission("system:message:template:query")
+ @GetMapping("/{id}")
+ public R getInfo(@NotNull(message = "消息模板ID不能为空") @PathVariable Long id) {
+ return R.ok(templateService.selectTemplateById(id));
+ }
+
+ /**
+ * 新增消息模板
+ */
+ @SaCheckPermission("system:message:template:add")
+ @Log(title = "消息模板管理", businessType = BusinessType.INSERT)
+ @RepeatSubmit()
+ @PostMapping()
+ public R add(@Validated(AddGroup.class) @RequestBody SysMessageTemplateBo bo) {
+ return toAjax(templateService.insertTemplate(bo));
+ }
+
+ /**
+ * 修改消息模板
+ */
+ @SaCheckPermission("system:message:template:edit")
+ @Log(title = "消息模板管理", businessType = BusinessType.UPDATE)
+ @RepeatSubmit()
+ @PutMapping()
+ public R edit(@Validated(EditGroup.class) @RequestBody SysMessageTemplateBo bo) {
+ return toAjax(templateService.updateTemplate(bo));
+ }
+
+ /**
+ * 删除消息模板
+ *
+ * @param ids 消息模板ID串
+ */
+ @SaCheckPermission("system:message:template:remove")
+ @Log(title = "消息模板管理", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public R remove(@NotEmpty(message = "消息模板ID不能为空") @PathVariable Long[] ids) {
+ return toAjax(templateService.deleteTemplateByIds(ids));
+ }
+}
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/converter/SysMessageConvert.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/converter/SysMessageConvert.java
new file mode 100644
index 000000000..11fe544f8
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/converter/SysMessageConvert.java
@@ -0,0 +1,39 @@
+package org.dromara.system.converter;
+
+import org.dromara.system.domain.SysMessage;
+import org.dromara.system.domain.vo.SysMessageVo;
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+
+import java.util.List;
+
+/**
+ * 消息对象转换器
+ *
+ * @author ruoyi
+ */
+@Mapper(componentModel = "spring")
+public interface SysMessageConvert {
+
+ SysMessageConvert INSTANCE = Mappers.getMapper(SysMessageConvert.class);
+
+ /**
+ * SysMessage转SysMessageVo
+ */
+ SysMessageVo convert(SysMessage sysMessage);
+
+ /**
+ * SysMessage列表转SysMessageVo列表
+ */
+ List convertList(List sysMessageList);
+
+ /**
+ * SysMessageVo转SysMessage
+ */
+ SysMessage convert(SysMessageVo sysMessageVo);
+
+ /**
+ * SysMessageVo列表转SysMessage列表
+ */
+ List convertListVoToEntity(List sysMessageVoList);
+}
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMessage.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMessage.java
new file mode 100644
index 000000000..88de0ca71
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMessage.java
@@ -0,0 +1,49 @@
+package org.dromara.system.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 org.dromara.common.tenant.core.TenantEntity;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 消息对象 sys_message
+ *
+ * @author ruoyi
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_message")
+public class SysMessage extends BaseEntity {
+
+ private static final long serialVersionUID = 1L;
+
+ /** 主键ID */
+ @TableId(value = "id")
+ private Long id;
+
+ /** 消息标题 */
+ private String title;
+
+ /** 消息内容 */
+ private String content;
+
+ /** 消息类型(AUTO自动/MANUAL手动) */
+ private String msgType;
+
+ /** 触发条件 */
+ private String subType;
+
+ /** 发送者ID */
+ private Long senderId;
+
+ /** 定时发送时间 */
+ private Date scheduledTime;
+
+// /** 状态(0正常 1停用) */
+// private String status;
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMessageTemplate.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMessageTemplate.java
new file mode 100644
index 000000000..26c6bc738
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMessageTemplate.java
@@ -0,0 +1,62 @@
+package org.dromara.system.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 org.dromara.common.tenant.core.TenantEntity;
+
+/**
+ * 消息模板对象 sys_message_template
+ *
+ * @author ruoyi
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_message_template")
+public class SysMessageTemplate extends BaseEntity {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 模板ID
+ */
+ @TableId(value = "id")
+ private Long id;
+
+ /**
+ * 模板类型(1通知 2公告 3消息)
+ */
+ private String templateType;
+
+ /**
+ * 模板编码
+ */
+ private String templateCode;
+
+ /**
+ * 模板名称
+ */
+ private String templateName;
+
+ /**
+ * 模板内容
+ */
+ private String templateContent;
+
+ /**
+ * 模板参数
+ */
+ private String templateParams;
+
+ /**
+ * 状态(0正常 1停用)
+ */
+ private String status;
+
+ /**
+ * 备注
+ */
+ private String remark;
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMessageUser.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMessageUser.java
new file mode 100644
index 000000000..8994159c1
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMessageUser.java
@@ -0,0 +1,49 @@
+package org.dromara.system.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 org.dromara.common.tenant.core.TenantEntity;
+
+import java.util.Date;
+
+/**
+ * 消息用户关联对象 sys_message_user
+ *
+ * @author ruoyi
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_message_user")
+public class SysMessageUser extends BaseEntity {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 主键ID
+ */
+ @TableId(value = "id")
+ private Long id;
+
+ /**
+ * 消息ID
+ */
+ private Long messageId;
+
+ /**
+ * 用户ID
+ */
+ private Long userId;
+
+ /**
+ * 是否已读(0未读 1已读)
+ */
+ private Boolean isRead;
+
+ /**
+ * 阅读时间
+ */
+ private Date readTime;
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMessageBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMessageBo.java
new file mode 100644
index 000000000..5082bc6da
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMessageBo.java
@@ -0,0 +1,104 @@
+package org.dromara.system.domain.bo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.system.domain.SysMessage;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 消息业务对象
+ *
+ * @author ruoyi
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ExcelIgnoreUnannotated
+public class SysMessageBo extends BaseEntity {
+
+ /** 主键ID */
+ @ExcelProperty(value = "消息ID")
+ private Long id;
+
+ /** 消息标题 */
+ @NotBlank(message = "消息标题不能为空", groups = { AddGroup.class, EditGroup.class })
+ @Size(min = 0, max = 100, message = "消息标题长度不能超过100个字符")
+ @ExcelProperty(value = "消息标题")
+ private String title;
+
+ /** 消息内容 */
+ @NotBlank(message = "消息内容不能为空", groups = { AddGroup.class, EditGroup.class })
+ @ExcelProperty(value = "消息内容")
+ private String content;
+
+ /** 消息类型(AUTO自动/MANUAL手动) */
+ @NotBlank(message = "消息类型不能为空", groups = { AddGroup.class, EditGroup.class })
+ @ExcelProperty(value = "消息类型")
+ private String msgType;
+
+ /** 触发条件 */
+ @ExcelProperty(value = "触发条件")
+ private String subType;
+
+ /** 发送者ID */
+ @ExcelProperty(value = "发送者ID")
+ private Long senderId;
+
+ /** 定时发送时间 */
+ @ExcelProperty(value = "定时发送时间")
+ private Date scheduledTime;
+
+// /** 状态(0正常 1停用) */
+// @ExcelProperty(value = "状态")
+// private String status;
+
+ /** 发送范围(all:全部用户, userType:按用户类型, userIds:指定用户) */
+ private String sendScope;
+
+ /** 接收用户ID列表 */
+ private List userIds;
+
+// /** 用户类型(1普通用户 2商家 3达人 4代理) */
+// private String userType;
+
+ /** 是否发送给所有用户 */
+ private Boolean sendToAll;
+
+ public SysMessage toEntity() {
+ SysMessage entity = new SysMessage();
+ entity.setId(this.getId());
+ entity.setTitle(this.getTitle());
+ entity.setContent(this.getContent());
+ entity.setMsgType(this.getMsgType());
+ entity.setSubType(this.getSubType());
+ entity.setSenderId(this.getSenderId());
+ entity.setScheduledTime(this.getScheduledTime());
+// entity.setStatus(this.getStatus());
+ entity.setCreateBy(this.getCreateBy());
+ entity.setCreateTime(this.getCreateTime());
+ entity.setUpdateBy(this.getUpdateBy());
+ entity.setUpdateTime(this.getUpdateTime());
+ return entity;
+ }
+
+ /**
+ * 转换为查询条件
+ */
+ public LambdaQueryWrapper toWrapper() {
+ LambdaQueryWrapper lqw = new LambdaQueryWrapper<>();
+ lqw.like(StringUtils.isNotBlank(this.getTitle()), SysMessage::getTitle, this.getTitle())
+ .eq(StringUtils.isNotBlank(this.getMsgType()), SysMessage::getMsgType, this.getMsgType())
+ .orderByDesc(SysMessage::getCreateTime);
+ return lqw;
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMessageTemplateBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMessageTemplateBo.java
new file mode 100644
index 000000000..fc6cca4ec
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMessageTemplateBo.java
@@ -0,0 +1,90 @@
+package org.dromara.system.domain.bo;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.system.domain.SysMessageTemplate;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+
+/**
+ * 消息模板业务对象 sys_message_template
+ *
+ * @author ruoyi
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class SysMessageTemplateBo extends BaseEntity {
+
+ /**
+ * 模板ID
+ */
+ @NotNull(message = "模板ID不能为空", groups = { EditGroup.class })
+ private Long id;
+
+ /**
+ * 模板类型(1通知 2公告 3消息)
+ */
+ @NotBlank(message = "模板类型不能为空", groups = { AddGroup.class, EditGroup.class })
+ private String templateType;
+
+ /**
+ * 模板编码
+ */
+ @NotBlank(message = "模板编码不能为空", groups = { AddGroup.class, EditGroup.class })
+ @Size(min = 0, max = 64, message = "模板编码长度不能超过64个字符")
+ private String templateCode;
+
+ /**
+ * 模板名称
+ */
+ @NotBlank(message = "模板名称不能为空", groups = { AddGroup.class, EditGroup.class })
+ @Size(min = 0, max = 100, message = "模板名称长度不能超过100个字符")
+ private String templateName;
+
+ /**
+ * 模板内容
+ */
+ @NotBlank(message = "模板内容不能为空", groups = { AddGroup.class, EditGroup.class })
+ private String templateContent;
+
+ /**
+ * 模板参数
+ */
+ private String templateParams;
+
+// /**
+// * 状态(0正常 1停用)
+// */
+// @NotBlank(message = "状态不能为空", groups = { AddGroup.class, EditGroup.class })
+// private String status;
+
+ /**
+ * 备注
+ */
+ private String remark;
+
+ /**
+ * 转换为实体对象
+ */
+ public SysMessageTemplate toEntity() {
+ SysMessageTemplate entity = new SysMessageTemplate();
+ entity.setId(this.getId());
+ entity.setTemplateType(this.getTemplateType());
+ entity.setTemplateCode(this.getTemplateCode());
+ entity.setTemplateName(this.getTemplateName());
+ entity.setTemplateContent(this.getTemplateContent());
+ entity.setTemplateParams(this.getTemplateParams());
+// entity.setStatus(this.getStatus());
+ entity.setRemark(this.getRemark());
+ entity.setCreateBy(this.getCreateBy());
+ entity.setCreateTime(this.getCreateTime());
+ entity.setUpdateBy(this.getUpdateBy());
+ entity.setUpdateTime(this.getUpdateTime());
+ return entity;
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/event/MessageEvent.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/event/MessageEvent.java
new file mode 100644
index 000000000..9cea99281
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/event/MessageEvent.java
@@ -0,0 +1,23 @@
+package org.dromara.system.domain.event;
+
+import lombok.Getter;
+import org.dromara.system.domain.vo.SysMessageVo;
+import org.springframework.context.ApplicationEvent;
+
+/**
+ * 消息事件
+ *
+ * @author ruoyi
+ */
+@Getter
+public class MessageEvent extends ApplicationEvent {
+
+ private final SysMessageVo message;
+ private final Long userId;
+
+ public MessageEvent(Object source, SysMessageVo message, Long userId) {
+ super(source);
+ this.message = message;
+ this.userId = userId;
+ }
+}
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMessageTemplateVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMessageTemplateVo.java
new file mode 100644
index 000000000..958fe5b61
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMessageTemplateVo.java
@@ -0,0 +1,59 @@
+package org.dromara.system.domain.vo;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.tenant.core.TenantEntity;
+
+import java.io.Serializable;
+
+/**
+ * 消息模板视图对象 sys_message_template
+ *
+ * @author ruoyi
+ */
+@Data
+//@EqualsAndHashCode(callSuper = true)
+public class SysMessageTemplateVo implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 模板ID
+ */
+ private Long id;
+
+ /**
+ * 模板类型(1通知 2公告 3消息)
+ */
+ private String templateType;
+
+ /**
+ * 模板编码
+ */
+ private String templateCode;
+
+ /**
+ * 模板名称
+ */
+ private String templateName;
+
+ /**
+ * 模板内容
+ */
+ private String templateContent;
+
+ /**
+ * 模板参数
+ */
+ private String templateParams;
+
+// /**
+// * 状态(0正常 1停用)
+// */
+// private String status;
+
+ /**
+ * 备注
+ */
+ private String remark;
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMessageUserVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMessageUserVo.java
new file mode 100644
index 000000000..635c1beb1
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMessageUserVo.java
@@ -0,0 +1,45 @@
+package org.dromara.system.domain.vo;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.tenant.core.TenantEntity;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 消息用户关联视图对象 sys_message_user
+ *
+ * @author ruoyi
+ */
+@Data
+//@EqualsAndHashCode(callSuper = true)
+public class SysMessageUserVo implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 主键ID
+ */
+ private Long id;
+
+ /**
+ * 消息ID
+ */
+ private Long messageId;
+
+ /**
+ * 用户ID
+ */
+ private Long userId;
+
+ /**
+ * 是否已读(0未读 1已读)
+ */
+ private Boolean isRead;
+
+ /**
+ * 阅读时间
+ */
+ private Date readTime;
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMessageVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMessageVo.java
new file mode 100644
index 000000000..455a29e47
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMessageVo.java
@@ -0,0 +1,65 @@
+package org.dromara.system.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.system.domain.SysMessage;
+import org.dromara.system.domain.SysNotice;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 消息视图对象
+ *
+ * @author ruoyi
+ */
+@Data
+@AutoMapper(target = SysMessage.class)
+public class SysMessageVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /** 主键ID */
+ @ExcelProperty(value = "消息ID")
+ private Long id;
+
+ /** 消息标题 */
+ @ExcelProperty(value = "消息标题")
+ private String title;
+
+ /** 消息内容 */
+ @ExcelProperty(value = "消息内容")
+ private String content;
+
+ /** 消息类型(AUTO自动/MANUAL手动) */
+ @ExcelProperty(value = "消息类型")
+ private String msgType;
+
+ /** 触发条件 */
+ @ExcelProperty(value = "触发条件")
+ private String subType;
+
+ /** 发送者ID */
+ @ExcelProperty(value = "发送者ID")
+ private Long senderId;
+
+ /** 发送者名称 */
+ @ExcelProperty(value = "发送者")
+ private String senderName;
+
+ /** 定时发送时间 */
+ @ExcelProperty(value = "定时发送时间")
+ private Date scheduledTime;
+
+// /** 状态(0正常 1停用) */
+// @ExcelProperty(value = "状态")
+// private String status;
+
+ /** 创建时间 */
+ @ExcelProperty(value = "创建时间")
+ private Date createTime;
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/event/MessageEventListener.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/event/MessageEventListener.java
new file mode 100644
index 000000000..0c38d1c0e
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/event/MessageEventListener.java
@@ -0,0 +1,35 @@
+package org.dromara.system.event;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.system.domain.event.MessageEvent;
+import org.dromara.system.websocket.MessageWebSocketServer;
+import org.springframework.context.event.EventListener;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Component;
+
+/**
+ * 消息事件监听器
+ *
+ * @author ruoyi
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class MessageEventListener {
+
+ private final MessageWebSocketServer messageWebSocketServer;
+
+ /**
+ * 处理消息事件
+ */
+ @Async
+ @EventListener
+ public void handleMessageEvent(MessageEvent event) {
+ try {
+ messageWebSocketServer.sendMessage(event.getUserId(), String.valueOf(event.getMessage()));
+ } catch (Exception e) {
+ log.error("处理消息事件失败", e);
+ }
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMessageMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMessageMapper.java
new file mode 100644
index 000000000..03bcd9c77
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMessageMapper.java
@@ -0,0 +1,23 @@
+package org.dromara.system.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.dromara.system.domain.SysMessage;
+import org.dromara.system.domain.vo.SysMessageVo;
+
+/**
+ * 消息Mapper接口
+ *
+ * @author ruoyi
+ */
+public interface SysMessageMapper extends BaseMapper {
+
+ /**
+ * 查询用户未读消息分页列表
+ *
+ * @param page 分页参数
+ * @param userId 用户ID
+ * @return 消息分页列表
+ */
+ Page selectPageUnreadMessages(Page page, Long userId);
+}
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMessageTemplateMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMessageTemplateMapper.java
new file mode 100644
index 000000000..7220814e7
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMessageTemplateMapper.java
@@ -0,0 +1,14 @@
+package org.dromara.system.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysMessageTemplate;
+import org.dromara.system.domain.vo.SysMessageTemplateVo;
+
+/**
+ * 消息模板Mapper接口
+ *
+ * @author ruoyi
+ */
+public interface SysMessageTemplateMapper extends BaseMapperPlus {
+
+}
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMessageUserMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMessageUserMapper.java
new file mode 100644
index 000000000..13730aa4b
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMessageUserMapper.java
@@ -0,0 +1,32 @@
+package org.dromara.system.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysMessageUser;
+import org.dromara.system.domain.vo.SysMessageUserVo;
+
+/**
+ * 消息用户关联Mapper接口
+ *
+ * @author ruoyi
+ */
+public interface SysMessageUserMapper extends BaseMapperPlus {
+
+ /**
+ * 更新消息读取状态
+ *
+ * @param messageId 消息ID
+ * @param userId 用户ID
+ * @param isRead 是否已读
+ * @return 结果
+ */
+ default int updateReadStatus(Long messageId, Long userId, boolean isRead) {
+ LambdaQueryWrapper lqw = Wrappers.lambdaQuery();
+ lqw.eq(SysMessageUser::getMessageId, messageId)
+ .eq(SysMessageUser::getUserId, userId);
+ SysMessageUser messageUser = new SysMessageUser();
+ messageUser.setIsRead(isRead);
+ return update(messageUser, lqw);
+ }
+}
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java
index 46695aa4c..99a25cb33 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java
@@ -120,4 +120,19 @@ public interface SysUserMapper extends BaseMapperPlus {
})
int updateById(@Param(Constants.ENTITY) SysUser user);
+ /**
+ * 根据用户类型查询用户ID列表
+ *
+ * @param userType 用户类型
+ * @return 用户ID列表
+ */
+ List selectUserIdsByType(@Param("userType") String userType);
+
+ /**
+ * 查询所有用户ID
+ *
+ * @return 用户ID列表
+ */
+ List selectAllUserIds();
+
}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/IMessageWebSocketService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/IMessageWebSocketService.java
new file mode 100644
index 000000000..ce321e34d
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/IMessageWebSocketService.java
@@ -0,0 +1,26 @@
+package org.dromara.system.service;
+
+import org.dromara.system.domain.vo.SysMessageVo;
+
+/**
+ * WebSocket消息服务接口
+ *
+ * @author ruoyi
+ */
+public interface IMessageWebSocketService {
+
+ /**
+ * 发送消息给指定用户
+ *
+ * @param userId 用户ID
+ * @param message 消息内容
+ */
+ void sendMessage(Long userId, SysMessageVo message);
+
+ /**
+ * 广播消息给所有在线用户
+ *
+ * @param message 消息内容
+ */
+ void broadcastMessage(SysMessageVo message);
+}
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMessageService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMessageService.java
new file mode 100644
index 000000000..158346f4b
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMessageService.java
@@ -0,0 +1,136 @@
+package org.dromara.system.service;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+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.system.domain.SysMessage;
+import org.dromara.system.domain.bo.SysMessageBo;
+import org.dromara.system.domain.vo.SysMessageVo;
+
+import java.util.List;
+
+/**
+ * 消息Service接口
+ *
+ * @author ruoyi
+ */
+public interface ISysMessageService extends IService {
+
+ /**
+ * 分页查询消息列表
+ */
+ TableDataInfo selectPageMessageList(SysMessageBo bo, PageQuery pageQuery);
+
+ /**
+ * 发送消息给指定用户
+ *
+ * @param message 消息内容
+ * @param userId 用户ID
+ * @return 结果
+ */
+ int sendMessageToUser(SysMessageBo message, Long userId);
+
+ /**
+ * 发送消息给多个用户
+ *
+ * @param message 消息内容
+ * @param userIds 用户ID列表
+ * @return 结果
+ */
+ int sendMessageToUsers(SysMessageBo message, List userIds);
+
+ /**
+ * 发送自动消息
+ *
+ * @param message 消息信息
+ * @param userIds 用户ID列表
+ * @return 结果
+ */
+ int sendAutoMessage(SysMessageBo message, List userIds);
+
+ /**
+ * 标记消息为已读
+ *
+ * @param messageId 消息ID
+ * @param userId 用户ID
+ * @return 结果
+ */
+ int markAsRead(Long messageId, Long userId);
+
+ /**
+ * 查询用户未读消息分页列表
+ *
+ * @param userId 用户ID
+ * @param pageQuery 分页参数
+ * @return 消息分页列表
+ */
+ TableDataInfo selectPageUnreadMessages(Long userId, PageQuery pageQuery);
+
+ /**
+ * 查询用户已读消息分页列表
+ *
+ * @param userId 用户ID
+ * @param pageQuery 分页参数
+ * @return 消息分页列表
+ */
+ TableDataInfo selectPageReadMessages(Long userId, PageQuery pageQuery);
+
+ /**
+ * 查询消息列表
+ *
+ * @param message 消息信息
+ * @return 消息列表
+ */
+ List selectMessageList(SysMessageBo message);
+
+ /**
+ * 查询消息详细信息
+ *
+ * @param id 消息ID
+ * @return 消息信息
+ */
+ SysMessageVo selectMessageById(Long id);
+
+ /**
+ * 新增消息
+ *
+ * @param message 消息信息
+ * @return 结果
+ */
+ int insertMessage(SysMessageBo message);
+
+ /**
+ * 修改消息
+ *
+ * @param message 消息信息
+ * @return 结果
+ */
+ int updateMessage(SysMessageBo message);
+
+ /**
+ * 批量删除消息
+ *
+ * @param ids 需要删除的消息ID数组
+ * @return 结果
+ */
+ int deleteMessageByIds(Long[] ids);
+
+ /**
+ * 删除消息信息
+ *
+ * @param id 消息ID
+ * @return 结果
+ */
+ int deleteMessageById(Long id);
+
+ /**
+ * 将BO对象转换为查询条件
+ *
+ * @param bo 业务对象
+ * @return 查询条件
+ */
+ LambdaQueryWrapper toWrapper(SysMessageBo bo);
+
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMessageTemplateService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMessageTemplateService.java
new file mode 100644
index 000000000..c53b0ec44
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMessageTemplateService.java
@@ -0,0 +1,75 @@
+package org.dromara.system.service;
+
+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.system.domain.SysMessageTemplate;
+import org.dromara.system.domain.bo.SysMessageTemplateBo;
+import org.dromara.system.domain.vo.SysMessageTemplateVo;
+
+import java.util.List;
+
+/**
+ * 消息模板Service接口
+ *
+ * @author ruoyi
+ */
+public interface ISysMessageTemplateService extends IService {
+
+ /**
+ * 查询消息模板列表
+ *
+ * @param template 消息模板信息
+ * @return 消息模板列表
+ */
+ List selectTemplateList(SysMessageTemplateBo template);
+
+ /**
+ * 查询消息模板分页列表
+ *
+ * @param template 消息模板信息
+ * @param pageQuery 分页参数
+ * @return 消息模板分页列表
+ */
+ TableDataInfo selectTemplatePage(SysMessageTemplateBo template, PageQuery pageQuery);
+
+ /**
+ * 查询消息模板详细信息
+ *
+ * @param id 消息模板ID
+ * @return 消息模板信息
+ */
+ SysMessageTemplateVo selectTemplateById(Long id);
+
+ /**
+ * 新增消息模板
+ *
+ * @param template 消息模板信息
+ * @return 结果
+ */
+ int insertTemplate(SysMessageTemplateBo template);
+
+ /**
+ * 修改消息模板
+ *
+ * @param template 消息模板信息
+ * @return 结果
+ */
+ int updateTemplate(SysMessageTemplateBo template);
+
+ /**
+ * 批量删除消息模板
+ *
+ * @param ids 需要删除的消息模板ID数组
+ * @return 结果
+ */
+ int deleteTemplateByIds(Long[] ids);
+
+ /**
+ * 删除消息模板信息
+ *
+ * @param id 消息模板ID
+ * @return 结果
+ */
+ int deleteTemplateById(Long id);
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/MessageWebSocketServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/MessageWebSocketServiceImpl.java
new file mode 100644
index 000000000..9af04a16c
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/MessageWebSocketServiceImpl.java
@@ -0,0 +1,31 @@
+package org.dromara.system.service.impl;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.system.domain.vo.SysMessageVo;
+import org.dromara.system.service.IMessageWebSocketService;
+import org.dromara.system.websocket.MessageWebSocketServer;
+import org.springframework.stereotype.Service;
+
+/**
+ * WebSocket消息服务实现类
+ *
+ * @author ruoyi
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class MessageWebSocketServiceImpl implements IMessageWebSocketService {
+
+ private final MessageWebSocketServer messageWebSocketServer;
+
+ @Override
+ public void sendMessage(Long userId, SysMessageVo message) {
+ messageWebSocketServer.sendMessage(userId, String.valueOf(message));
+ }
+
+ @Override
+ public void broadcastMessage(SysMessageVo message) {
+ messageWebSocketServer.broadcastMessage(String.valueOf(message));
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMessageServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMessageServiceImpl.java
new file mode 100644
index 000000000..896b8b9c2
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMessageServiceImpl.java
@@ -0,0 +1,182 @@
+package org.dromara.system.service.impl;
+
+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 lombok.RequiredArgsConstructor;
+import org.dromara.common.core.utils.MapstructUtils;
+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.system.domain.SysMessage;
+import org.dromara.system.domain.SysMessageUser;
+import org.dromara.system.domain.bo.SysMessageBo;
+import org.dromara.system.domain.event.MessageEvent;
+import org.dromara.system.domain.vo.SysMessageVo;
+import org.dromara.system.mapper.SysMessageMapper;
+import org.dromara.system.mapper.SysMessageUserMapper;
+import org.dromara.system.service.ISysMessageService;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+/**
+ * 消息Service业务层处理
+ *
+ * @author ruoyi
+ */
+@Service
+@RequiredArgsConstructor
+public class SysMessageServiceImpl extends ServiceImpl implements ISysMessageService {
+
+ private final SysMessageMapper messageMapper;
+ private final SysMessageUserMapper messageUserMapper;
+ private final ApplicationEventPublisher eventPublisher;
+
+ @Override
+ public TableDataInfo selectPageMessageList(SysMessageBo bo, PageQuery pageQuery) {
+ LambdaQueryWrapper lqw = new LambdaQueryWrapper<>();
+ lqw.like(StringUtils.isNotBlank(bo.getTitle()), SysMessage::getTitle, bo.getTitle())
+ .eq(StringUtils.isNotBlank(bo.getMsgType()), SysMessage::getMsgType, bo.getMsgType())
+// .eq(StringUtils.isNotBlank(bo.getStatus()), SysMessage::getStatus, bo.getStatus())
+ .orderByDesc(SysMessage::getCreateTime);
+ Page page = messageMapper.selectPage(pageQuery.build(), lqw);
+ List records = MapstructUtils.convert(page.getRecords(), SysMessageVo.class);
+ Page voPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
+ voPage.setRecords(records);
+ return TableDataInfo.build(voPage);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int sendMessageToUser(SysMessageBo message, Long userId) {
+ // 保存消息
+ SysMessage entity = message.toEntity();
+ messageMapper.insert(entity);
+ // 创建消息用户关联
+ SysMessageUser messageUser = new SysMessageUser();
+ messageUser.setMessageId(entity.getId());
+ messageUser.setUserId(userId);
+ messageUser.setIsRead(false);
+ int rows = messageUserMapper.insert(messageUser);
+ // 发送WebSocket消息
+ if (rows > 0) {
+ SysMessageVo messageVo = MapstructUtils.convert(entity, SysMessageVo.class);
+ eventPublisher.publishEvent(new MessageEvent(this, messageVo, userId));
+ }
+ return rows;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int sendMessageToUsers(SysMessageBo message, List userIds) {
+ // 保存消息
+ SysMessage entity = message.toEntity();
+ messageMapper.insert(entity);
+ // 批量创建消息用户关联
+ int count = 0;
+ for (Long userId : userIds) {
+ SysMessageUser messageUser = new SysMessageUser();
+ messageUser.setMessageId(entity.getId());
+ messageUser.setUserId(userId);
+ messageUser.setIsRead(false);
+ int rows = messageUserMapper.insert(messageUser);
+ if (rows > 0) {
+ count++;
+ // 发送WebSocket消息
+ SysMessageVo messageVo = MapstructUtils.convert(entity, SysMessageVo.class);
+ eventPublisher.publishEvent(new MessageEvent(this, messageVo, userId));
+ }
+ }
+ return count;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int sendAutoMessage(SysMessageBo message, List userIds) {
+ message.setMsgType("AUTO");
+ return sendMessageToUsers(message, userIds);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int markAsRead(Long messageId, Long userId) {
+ LambdaQueryWrapper lqw = new LambdaQueryWrapper<>();
+ lqw.eq(SysMessageUser::getMessageId, messageId)
+ .eq(SysMessageUser::getUserId, userId);
+ SysMessageUser messageUser = new SysMessageUser();
+ messageUser.setIsRead(true);
+ return messageUserMapper.update(messageUser, lqw);
+ }
+
+ @Override
+ public TableDataInfo selectPageUnreadMessages(Long userId, PageQuery pageQuery) {
+ Page page = messageMapper.selectPageUnreadMessages(pageQuery.build(), userId);
+ return TableDataInfo.build(page);
+ }
+
+ @Override
+ public TableDataInfo selectPageReadMessages(Long userId, PageQuery pageQuery) {
+ LambdaQueryWrapper lqw = new LambdaQueryWrapper<>();
+// lqw.eq(SysMessage::getStatus, "0")
+// .inSql(SysMessage::getId,
+// "SELECT message_id FROM sys_message_user WHERE user_id = " + userId + " AND is_read = 1")
+// .orderByDesc(SysMessage::getCreateTime);
+//
+ Page page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
+ Page resultPage = messageMapper.selectPage(page, lqw);
+ List records = MapstructUtils.convert(resultPage.getRecords(), SysMessageVo.class);
+ Page voPage = new Page<>(resultPage.getCurrent(), resultPage.getSize(), resultPage.getTotal());
+ voPage.setRecords(records);
+ return TableDataInfo.build(voPage);
+ }
+
+ @Override
+ public List selectMessageList(SysMessageBo message) {
+ LambdaQueryWrapper lqw = new LambdaQueryWrapper<>();
+ lqw.eq(StringUtils.isNotBlank(message.getMsgType()), SysMessage::getMsgType, message.getMsgType())
+ .eq(StringUtils.isNotBlank(message.getSubType()), SysMessage::getSubType, message.getSubType())
+ .eq(message.getSenderId() != null, SysMessage::getSenderId, message.getSenderId())
+// .eq(StringUtils.isNotBlank(message.getStatus()), SysMessage::getStatus, message.getStatus())
+ .orderByDesc(SysMessage::getCreateTime);
+ return MapstructUtils.convert(messageMapper.selectList(lqw), SysMessageVo.class);
+ }
+
+ @Override
+ public SysMessageVo selectMessageById(Long id) {
+ return MapstructUtils.convert(messageMapper.selectById(id), SysMessageVo.class);
+ }
+
+ @Override
+ public int insertMessage(SysMessageBo message) {
+ return messageMapper.insert(message.toEntity());
+ }
+
+ @Override
+ public int updateMessage(SysMessageBo message) {
+ return messageMapper.updateById(message.toEntity());
+ }
+
+ @Override
+ public int deleteMessageByIds(Long[] ids) {
+ return messageMapper.deleteBatchIds(List.of(ids));
+ }
+
+ @Override
+ public int deleteMessageById(Long id) {
+ return messageMapper.deleteById(id);
+ }
+
+ @Override
+ public LambdaQueryWrapper toWrapper(SysMessageBo bo) {
+ LambdaQueryWrapper lqw = new LambdaQueryWrapper<>();
+ lqw.like(StringUtils.isNotBlank(bo.getTitle()), SysMessage::getTitle, bo.getTitle())
+ .eq(StringUtils.isNotBlank(bo.getMsgType()), SysMessage::getMsgType, bo.getMsgType())
+ .orderByDesc(SysMessage::getCreateTime);
+ return lqw;
+ }
+
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMessageTemplateServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMessageTemplateServiceImpl.java
new file mode 100644
index 000000000..c859018d4
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMessageTemplateServiceImpl.java
@@ -0,0 +1,83 @@
+package org.dromara.system.service.impl;
+
+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 lombok.RequiredArgsConstructor;
+import org.dromara.common.core.utils.MapstructUtils;
+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.system.domain.SysMessageTemplate;
+import org.dromara.system.domain.bo.SysMessageTemplateBo;
+import org.dromara.system.domain.vo.SysMessageTemplateVo;
+import org.dromara.system.mapper.SysMessageTemplateMapper;
+import org.dromara.system.service.ISysMessageTemplateService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 消息模板Service业务层处理
+ *
+ * @author ruoyi
+ */
+@RequiredArgsConstructor
+@Service
+public class SysMessageTemplateServiceImpl extends ServiceImpl implements ISysMessageTemplateService {
+
+ private final SysMessageTemplateMapper templateMapper;
+
+ @Override
+ public TableDataInfo selectTemplatePage(SysMessageTemplateBo bo, PageQuery pageQuery) {
+ LambdaQueryWrapper lqw = new LambdaQueryWrapper<>();
+ lqw.eq(StringUtils.isNotBlank(bo.getTemplateType()), SysMessageTemplate::getTemplateType, bo.getTemplateType())
+ .eq(StringUtils.isNotBlank(bo.getStatus()), SysMessageTemplate::getStatus, bo.getStatus())
+ .like(StringUtils.isNotBlank(bo.getTemplateName()), SysMessageTemplate::getTemplateName, bo.getTemplateName())
+ .like(StringUtils.isNotBlank(bo.getTemplateCode()), SysMessageTemplate::getTemplateCode, bo.getTemplateCode())
+ .orderByDesc(SysMessageTemplate::getCreateTime);
+
+ Page page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
+ Page resultPage = templateMapper.selectPage(page, lqw);
+ List records = MapstructUtils.convert(resultPage.getRecords(), SysMessageTemplateVo.class);
+ Page voPage = new Page<>(resultPage.getCurrent(), resultPage.getSize(), resultPage.getTotal());
+ voPage.setRecords(records);
+ return TableDataInfo.build(voPage);
+ }
+
+ @Override
+ public List selectTemplateList(SysMessageTemplateBo bo) {
+ LambdaQueryWrapper lqw = new LambdaQueryWrapper<>();
+ lqw.eq(StringUtils.isNotBlank(bo.getTemplateType()), SysMessageTemplate::getTemplateType, bo.getTemplateType())
+ .eq(StringUtils.isNotBlank(bo.getStatus()), SysMessageTemplate::getStatus, bo.getStatus())
+ .like(StringUtils.isNotBlank(bo.getTemplateName()), SysMessageTemplate::getTemplateName, bo.getTemplateName())
+ .like(StringUtils.isNotBlank(bo.getTemplateCode()), SysMessageTemplate::getTemplateCode, bo.getTemplateCode())
+ .orderByDesc(SysMessageTemplate::getCreateTime);
+ return MapstructUtils.convert(templateMapper.selectList(lqw), SysMessageTemplateVo.class);
+ }
+
+ @Override
+ public SysMessageTemplateVo selectTemplateById(Long id) {
+ return MapstructUtils.convert(templateMapper.selectById(id), SysMessageTemplateVo.class);
+ }
+
+ @Override
+ public int insertTemplate(SysMessageTemplateBo bo) {
+ return templateMapper.insert(bo.toEntity());
+ }
+
+ @Override
+ public int updateTemplate(SysMessageTemplateBo bo) {
+ return templateMapper.updateById(bo.toEntity());
+ }
+
+ @Override
+ public int deleteTemplateByIds(Long[] ids) {
+ return templateMapper.deleteBatchIds(List.of(ids));
+ }
+
+ @Override
+ public int deleteTemplateById(Long id) {
+ return templateMapper.deleteById(id);
+ }
+}
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java
index a73415c64..ac115f736 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java
@@ -179,7 +179,7 @@ public class SysTenantServiceImpl implements ISysTenantService {
for (SysDictType dictType : dictTypeList) {
dictType.setDictId(null);
dictType.setTenantId(tenantId);
- dictType.setCreateDept(null);
+// dictType.setCreateDept(null);
dictType.setCreateBy(null);
dictType.setCreateTime(null);
dictType.setUpdateBy(null);
@@ -188,7 +188,7 @@ public class SysTenantServiceImpl implements ISysTenantService {
for (SysDictData dictData : dictDataList) {
dictData.setDictCode(null);
dictData.setTenantId(tenantId);
- dictData.setCreateDept(null);
+// dictData.setCreateDept(null);
dictData.setCreateBy(null);
dictData.setCreateTime(null);
dictData.setUpdateBy(null);
@@ -202,7 +202,7 @@ public class SysTenantServiceImpl implements ISysTenantService {
for (SysConfig config : sysConfigList) {
config.setConfigId(null);
config.setTenantId(tenantId);
- config.setCreateDept(null);
+// config.setCreateDept(null);
config.setCreateBy(null);
config.setCreateTime(null);
config.setUpdateBy(null);
@@ -448,7 +448,7 @@ public class SysTenantServiceImpl implements ISysTenantService {
data.setTenantId(tenantId);
data.setCreateTime(null);
data.setUpdateTime(null);
- data.setCreateDept(null);
+// data.setCreateDept(null);
data.setCreateBy(null);
data.setUpdateBy(null);
set.add(tenantId);
@@ -472,7 +472,7 @@ public class SysTenantServiceImpl implements ISysTenantService {
data.setTenantId(tenantId);
data.setCreateTime(null);
data.setUpdateTime(null);
- data.setCreateDept(null);
+// data.setCreateDept(null);
data.setCreateBy(null);
data.setUpdateBy(null);
set.add(tenantId);
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/task/MessageScheduledTask.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/task/MessageScheduledTask.java
new file mode 100644
index 000000000..9c4778efe
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/task/MessageScheduledTask.java
@@ -0,0 +1,78 @@
+package org.dromara.system.task;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.system.domain.SysMessage;
+//import org.dromara.system.domain.SysMessageUser;
+import org.dromara.system.domain.SysMessageUser;
+import org.dromara.system.domain.vo.SysMessageVo;
+import org.dromara.system.mapper.SysMessageMapper;
+//import org.dromara.system.mapper.SysMessageUserMapper
+import org.dromara.system.mapper.SysMessageUserMapper;
+import org.dromara.system.websocket.MessageWebSocketServer;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * 消息定时任务
+ *
+ * @author ruoyi
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class MessageScheduledTask {
+
+ private final SysMessageMapper messageMapper;
+ private final SysMessageUserMapper messageUserMapper;
+ private final MessageWebSocketServer messageWebSocketServer;
+
+ /**
+ * 每分钟执行一次,处理待发送的消息
+ */
+ @Scheduled(cron = "0 */1 * * * ?")
+ @Transactional(rollbackFor = Exception.class)
+ public void processScheduledMessages() {
+ log.info("开始处理定时消息...");
+ try {
+ // 查询待发送的消息
+ LambdaQueryWrapper lqw = new LambdaQueryWrapper<>();
+// lqw.eq(SysMessage::getStatus, "0")
+// .le(SysMessage::getScheduledTime, LocalDateTime.now())
+// .isNotNull(SysMessage::getScheduledTime);
+
+ List messages = messageMapper.selectList(lqw);
+
+ for (SysMessage message : messages) {
+ // 查询消息接收者
+ LambdaQueryWrapper userLqw = new LambdaQueryWrapper<>();
+ userLqw.eq(SysMessageUser::getMessageId, message.getId());
+ List messageUsers = messageUserMapper.selectList(userLqw);
+
+ // 发送消息
+ SysMessageVo messageVo = MapstructUtils.convert(message, SysMessageVo.class);
+ for (SysMessageUser messageUser : messageUsers) {
+ try {
+ messageWebSocketServer.sendMessage(messageUser.getUserId(), String.valueOf(messageVo));
+ } catch (Exception e) {
+ log.error("发送消息失败,消息ID:{},用户ID:{}", message.getId(), messageUser.getUserId(), e);
+ }
+ }
+
+ // 更新消息状态为已发送
+// message.setStatus("1");
+ messageMapper.updateById(message);
+ }
+
+ log.info("定时消息处理完成,共处理{}条消息", messages.size());
+ } catch (Exception e) {
+ log.error("处理定时消息时发生错误", e);
+ }
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/websocket/MessageWebSocketServer.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/websocket/MessageWebSocketServer.java
new file mode 100644
index 000000000..03ce98449
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/websocket/MessageWebSocketServer.java
@@ -0,0 +1,116 @@
+package org.dromara.system.websocket;
+
+import jakarta.websocket.*;
+import jakarta.websocket.server.ServerEndpoint;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.domain.model.LoginUser;
+import org.dromara.common.websocket.holder.WebSocketSessionHolder;
+import org.dromara.common.websocket.utils.WebSocketUtils;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 站内信 WebSocket 服务
+ */
+@Slf4j
+@Component
+@ServerEndpoint("/websocket/message")
+public class MessageWebSocketServer {
+
+ /**
+ * 用户ID和会话的映射关系
+ */
+ private static final Map SESSION_MAP = new ConcurrentHashMap<>();
+
+ /**
+ * 连接建立成功调用的方法
+ */
+ @OnOpen
+ public void onOpen(Session session) {
+ log.info("[WebSocket] 新的连接建立,sessionId: {}", session.getId());
+ try {
+ // 获取当前登录用户
+ LoginUser loginUser = (LoginUser) session.getUserProperties().get("loginUser");
+ if (loginUser != null) {
+ SESSION_MAP.put(loginUser.getUserId(), session);
+ log.info("[WebSocket] 用户 {} 连接成功", loginUser.getUserId());
+ } else {
+ log.warn("[WebSocket] 未获取到用户信息,关闭连接");
+ session.close();
+ }
+ } catch (Exception e) {
+ log.error("[WebSocket] 连接建立失败", e);
+ }
+ }
+
+ /**
+ * 连接关闭调用的方法
+ */
+ @OnClose
+ public void onClose(Session session) {
+ log.info("[WebSocket] 连接关闭,sessionId: {}", session.getId());
+ // 从映射中移除会话
+ SESSION_MAP.values().removeIf(s -> s.getId().equals(session.getId()));
+ }
+
+ /**
+ * 收到客户端消息后调用的方法
+ */
+ @OnMessage
+ public void onMessage(String message, Session session) {
+ log.info("[WebSocket] 收到消息: {}", message);
+ // 这里可以处理客户端发送的消息
+ }
+
+ /**
+ * 发生错误时调用
+ */
+ @OnError
+ public void onError(Session session, Throwable error) {
+ log.error("[WebSocket] 发生错误", error);
+ // 从映射中移除会话
+ SESSION_MAP.values().removeIf(s -> s.getId().equals(session.getId()));
+ }
+
+ /**
+ * 发送消息给指定用户
+ *
+ * @param userId 用户ID
+ * @param message 消息内容
+ */
+ public void sendMessage(Long userId, String message) {
+ Session session = SESSION_MAP.get(userId);
+ if (session != null && session.isOpen()) {
+ try {
+ session.getBasicRemote().sendText(message);
+ log.info("[WebSocket] 消息发送成功,接收者: {}", userId);
+ } catch (IOException e) {
+ log.error("[WebSocket] 消息发送失败", e);
+ }
+ } else {
+ log.warn("[WebSocket] 用户 {} 不在线或会话已关闭", userId);
+ }
+ }
+
+ /**
+ * 广播消息给所有在线用户
+ *
+ * @param message 消息内容
+ */
+ public void broadcastMessage(String message) {
+ SESSION_MAP.forEach((userId, session) -> {
+ if (session.isOpen()) {
+ try {
+ session.getBasicRemote().sendText(message);
+ log.info("[WebSocket] 广播消息发送成功,接收者: {}", userId);
+ } catch (IOException e) {
+ log.error("[WebSocket] 广播消息发送失败,接收者: {}", userId, e);
+ }
+ }
+ });
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/package-info.md b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/package-info.md
deleted file mode 100644
index c938b1e50..000000000
--- a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/package-info.md
+++ /dev/null
@@ -1,3 +0,0 @@
-java包使用 `.` 分割 resource 目录使用 `/` 分割
-
-此文件目的 防止文件夹粘连找不到 `xml` 文件
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMessageMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMessageMapper.xml
new file mode 100644
index 000000000..bc5135bf9
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMessageMapper.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMessageUserMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMessageUserMapper.xml
new file mode 100644
index 000000000..c89c93e52
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMessageUserMapper.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select id, message_id, user_id, is_read, read_time, create_time, update_time
+ from sys_message_user
+
+
+
+ update sys_message_user
+ set is_read = #{isRead},
+ read_time = sysdate()
+ where message_id = #{messageId}
+ and user_id = #{userId}
+
+
+
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
index ded6fa858..fdd5e84a4 100644
--- a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
+++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
@@ -69,5 +69,19 @@
select count(*) from sys_user where del_flag = '0' and user_id = #{userId}
+
+
+
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwDefinitionServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwDefinitionServiceImpl.java
index 7f0f67ec6..b725b783d 100644
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwDefinitionServiceImpl.java
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwDefinitionServiceImpl.java
@@ -220,7 +220,7 @@ public class FlwDefinitionServiceImpl implements IFlwDefinitionService {
.eq(FlowCategory::getTenantId, DEFAULT_TENANT_ID).eq(FlowCategory::getCategoryId, FlowConstant.FLOW_CATEGORY_ID));
flowCategory.setCategoryId(null);
flowCategory.setTenantId(tenantId);
- flowCategory.setCreateDept(null);
+// flowCategory.setCreateDept(null);
flowCategory.setCreateBy(null);
flowCategory.setCreateTime(null);
flowCategory.setUpdateBy(null);