diff --git a/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/constant/OrgTypeEnum.java b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/constant/OrgTypeEnum.java
new file mode 100644
index 000000000..09b109765
--- /dev/null
+++ b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/constant/OrgTypeEnum.java
@@ -0,0 +1,38 @@
+package com.pig4cloud.pigx.admin.api.constant;
+
+/**
+ * 组织类型
+ *
+ * @author lengleng
+ * @date 2023/11/15
+ */
+public enum OrgTypeEnum {
+
+ USER("user", "用户"), ROLE("role", "角色"), DEPT("dept", "部门");
+
+ private String type;
+
+ private String desc;
+
+ OrgTypeEnum(String type, String desc) {
+ this.type = type;
+ this.desc = desc;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public void setDesc(String desc) {
+ this.desc = desc;
+ }
+
+}
diff --git a/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/constant/ScheduleStateEnum.java b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/constant/ScheduleStateEnum.java
new file mode 100644
index 000000000..cf6f91221
--- /dev/null
+++ b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/constant/ScheduleStateEnum.java
@@ -0,0 +1,38 @@
+package com.pig4cloud.pigx.admin.api.constant;
+
+import lombok.Getter;
+
+/**
+ * @author lengleng
+ * @date 2023/11/14
+ *
+ * 日程状态枚举
+ */
+public enum ScheduleStateEnum {
+
+ /**
+ * 计划中
+ */
+ SCHEDULE("0", "计划中"),
+
+ /**
+ * 未开始
+ */
+ NOT_START("1", "未开始"),
+
+ /**
+ * 结束
+ */
+ END("3", "结束");
+
+ @Getter
+ private String code;
+
+ private String desc;
+
+ ScheduleStateEnum(String code, String desc) {
+ this.code = code;
+ this.desc = desc;
+ }
+
+}
diff --git a/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/constant/TenantStateEnum.java b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/constant/TenantStateEnum.java
new file mode 100644
index 000000000..6f2421955
--- /dev/null
+++ b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/constant/TenantStateEnum.java
@@ -0,0 +1,43 @@
+package com.pig4cloud.pigx.admin.api.constant;
+
+import lombok.Getter;
+
+/**
+ * 租户状态
+ *
+ * @author lengleng
+ * @date 2023/11/15
+ *
+ * "0" 正常 "9" 冻结
+ */
+public enum TenantStateEnum {
+
+ /**
+ * 正常
+ */
+ NORMAL("0", "正常"),
+
+ /**
+ * 冻结
+ */
+ FREEZE("9", "冻结");
+
+ @Getter
+ private final String code;
+
+ private final String desc;
+
+ TenantStateEnum(String code, String desc) {
+ this.code = code;
+ this.desc = desc;
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+}
diff --git a/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/constant/UserStateEnum.java b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/constant/UserStateEnum.java
new file mode 100644
index 000000000..0397ca88a
--- /dev/null
+++ b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/constant/UserStateEnum.java
@@ -0,0 +1,32 @@
+package com.pig4cloud.pigx.admin.api.constant;
+
+import lombok.Getter;
+
+/**
+ * 用户状态
+ *
+ * @author lengleng
+ * @date 2023/11/14
+ */
+public enum UserStateEnum {
+
+ /**
+ * 正常
+ */
+ NORMAL("0", "正常"),
+ /**
+ * 锁定
+ */
+ LOCK("9", "锁定");
+
+ @Getter
+ private final String code;
+
+ private final String desc;
+
+ UserStateEnum(String code, String desc) {
+ this.code = code;
+ this.desc = desc;
+ }
+
+}
diff --git a/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/entity/SysMessageEntity.java b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/entity/SysMessageEntity.java
new file mode 100644
index 000000000..552e1b1b7
--- /dev/null
+++ b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/entity/SysMessageEntity.java
@@ -0,0 +1,108 @@
+package com.pig4cloud.pigx.admin.api.entity;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.time.LocalDateTime;
+
+/**
+ * 站内信息
+ *
+ * @author pig
+ * @date 2023-10-25 13:37:25
+ */
+@Data
+@TableName("sys_message")
+@EqualsAndHashCode(callSuper = true)
+@Schema(description = "站内信息")
+public class SysMessageEntity extends Model {
+
+ /**
+ * 主键
+ */
+ @TableId(type = IdType.ASSIGN_ID)
+ @Schema(description = "主键")
+ private Long id;
+
+ /**
+ * 分类
+ */
+ @Schema(description = "分类 0-公告 1-站内信")
+ private String category;
+
+ /**
+ * 标题
+ */
+ @Schema(description = "标题")
+ private String title;
+
+ /**
+ * 内容
+ */
+ @Schema(description = "内容")
+ private String content;
+
+ /**
+ * 是否推送
+ */
+ @Schema(description = "是否推送")
+ private String sendFlag;
+
+ /**
+ * 通知全体
+ */
+ @Schema(description = "通知全体")
+ private String allFlag;
+
+ /**
+ * 排序 (越大越在前)
+ */
+ @Schema(description = "排序 (越大越在前)")
+ private Integer sort;
+
+ /**
+ * 创建人
+ */
+ @TableField(fill = FieldFill.INSERT)
+ @Schema(description = "创建人")
+ private String createBy;
+
+ /**
+ * 创建时间
+ */
+ @TableField(fill = FieldFill.INSERT)
+ @Schema(description = "创建时间")
+ private LocalDateTime createTime;
+
+ /**
+ * 更新人
+ */
+ @TableField(fill = FieldFill.INSERT_UPDATE)
+ @Schema(description = "更新人")
+ private String updateBy;
+
+ /**
+ * 更新时间
+ */
+ @TableField(fill = FieldFill.INSERT_UPDATE)
+ @Schema(description = "更新时间")
+ private LocalDateTime updateTime;
+
+ /**
+ * 删除时间
+ */
+ @TableLogic
+ @TableField(fill = FieldFill.INSERT)
+ @Schema(description = "删除时间")
+ private String delFlag;
+
+ /**
+ * 租户
+ */
+ @Schema(description = "租户")
+ private Long tenantId;
+
+}
diff --git a/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/entity/SysMessageRelationEntity.java b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/entity/SysMessageRelationEntity.java
new file mode 100644
index 000000000..711512947
--- /dev/null
+++ b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/entity/SysMessageRelationEntity.java
@@ -0,0 +1,96 @@
+package com.pig4cloud.pigx.admin.api.entity;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.time.LocalDateTime;
+
+/**
+ * 系统消息推送记录
+ *
+ * @author pig
+ * @date 2023-10-25 18:07:23
+ */
+@Data
+@TableName("sys_message_relation")
+@EqualsAndHashCode(callSuper = true)
+@Schema(description = "系统消息推送记录")
+public class SysMessageRelationEntity extends Model {
+
+ /**
+ * 主键
+ */
+ @TableId(type = IdType.ASSIGN_ID)
+ @Schema(description = "主键")
+ private Long id;
+
+ /**
+ * 消息ID
+ */
+ @Schema(description = "消息ID")
+ private Long msgId;
+
+ /**
+ * 接收人ID
+ */
+ @Schema(description = "接收人ID")
+ private Long userId;
+
+ /**
+ * 内容
+ */
+ @Schema(description = "内容")
+ private String content;
+
+ /**
+ * 已读(0否,1是)
+ */
+ @Schema(description = "已读(0否,1是)")
+ private String readFlag;
+
+ /**
+ * 创建人
+ */
+ @TableField(fill = FieldFill.INSERT)
+ @Schema(description = "创建人")
+ private String createBy;
+
+ /**
+ * 创建时间
+ */
+ @TableField(fill = FieldFill.INSERT)
+ @Schema(description = "创建时间")
+ private LocalDateTime createTime;
+
+ /**
+ * 更新人
+ */
+ @TableField(fill = FieldFill.INSERT_UPDATE)
+ @Schema(description = "更新人")
+ private String updateBy;
+
+ /**
+ * 更新时间
+ */
+ @TableField(fill = FieldFill.INSERT_UPDATE)
+ @Schema(description = "更新时间")
+ private LocalDateTime updateTime;
+
+ /**
+ * 删除时间
+ */
+ @TableLogic
+ @TableField(fill = FieldFill.INSERT)
+ @Schema(description = "删除时间")
+ private String delFlag;
+
+ /**
+ * 租户
+ */
+ @Schema(description = "租户")
+ private Long tenantId;
+
+}
diff --git a/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/vo/OrgTreeVO.java b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/vo/OrgTreeVO.java
new file mode 100644
index 000000000..812b3e78b
--- /dev/null
+++ b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/vo/OrgTreeVO.java
@@ -0,0 +1,45 @@
+package com.pig4cloud.pigx.admin.api.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @author : willian fu
+ * @version : 1.0
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class OrgTreeVO implements Serializable {
+
+ /**
+ * 用户od
+ */
+ private Long id;
+
+ /**
+ * 用户名称
+ */
+ private String name;
+
+ /**
+ * 类型
+ */
+ private String type;
+
+ /**
+ * 选择
+ */
+ private Boolean selected;
+
+ /**
+ * 头像
+ */
+ private String avatar;
+
+}
diff --git a/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/vo/SysMessageReadVO.java b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/vo/SysMessageReadVO.java
new file mode 100644
index 000000000..3d182b64b
--- /dev/null
+++ b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/vo/SysMessageReadVO.java
@@ -0,0 +1,30 @@
+package com.pig4cloud.pigx.admin.api.vo;
+
+import com.pig4cloud.pigx.admin.api.entity.SysMessageRelationEntity;
+import lombok.Data;
+
+/**
+ * 消息阅读vo
+ *
+ * @author lengleng
+ * @date 2023/10/26
+ */
+@Data
+public class SysMessageReadVO extends SysMessageRelationEntity {
+
+ /**
+ * 文章标题
+ */
+ private String title;
+
+ /**
+ * 用户名
+ */
+ private String username;
+
+ /**
+ * 姓名
+ */
+ private String name;
+
+}
diff --git a/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/vo/SysMessageVO.java b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/vo/SysMessageVO.java
new file mode 100644
index 000000000..76d4bb81b
--- /dev/null
+++ b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/vo/SysMessageVO.java
@@ -0,0 +1,28 @@
+package com.pig4cloud.pigx.admin.api.vo;
+
+import com.pig4cloud.pigx.admin.api.entity.SysMessageEntity;
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 消息发送实体
+ *
+ * @author lengleng
+ * @date 2023/10/25
+ */
+@Data
+public class SysMessageVO extends SysMessageEntity {
+
+ /**
+ * 是否已读
+ */
+ private String readFlag;
+
+ /**
+ * 发送用户列表
+ */
+ private List userList = new ArrayList<>();
+
+}
diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysMessageController.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysMessageController.java
new file mode 100644
index 000000000..4d0b2bf2b
--- /dev/null
+++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysMessageController.java
@@ -0,0 +1,169 @@
+package com.pig4cloud.pigx.admin.controller;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.pig4cloud.pigx.admin.api.entity.SysMessageEntity;
+import com.pig4cloud.pigx.admin.api.vo.SysMessageVO;
+import com.pig4cloud.pigx.admin.service.SysMessageService;
+import com.pig4cloud.pigx.common.core.util.R;
+import com.pig4cloud.pigx.common.excel.annotation.ResponseExcel;
+import com.pig4cloud.pigx.common.log.annotation.SysLog;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.security.SecurityRequirement;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.RequiredArgsConstructor;
+import org.springdoc.core.annotations.ParameterObject;
+import org.springframework.http.HttpHeaders;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 站内信息
+ *
+ * @author pig
+ * @date 2023-10-25 13:37:25
+ */
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/sysMessage")
+@Tag(description = "sysMessage", name = "站内信息管理")
+@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)
+public class SysMessageController {
+
+ private final SysMessageService sysMessageService;
+
+ /**
+ * 分页查询
+ * @param page 分页对象
+ * @param sysMessage 站内信息
+ * @return
+ */
+ @Operation(summary = "分页查询", description = "分页查询")
+ @GetMapping("/page")
+ @PreAuthorize("@pms.hasPermission('sys_message_view')")
+ public R getSysMessagePage(@ParameterObject Page page, @ParameterObject SysMessageEntity sysMessage) {
+ LambdaQueryWrapper wrapper = Wrappers.lambdaQuery();
+ wrapper.like(StrUtil.isNotBlank(sysMessage.getTitle()), SysMessageEntity::getTitle, sysMessage.getTitle());
+ return R.ok(sysMessageService.page(page, wrapper));
+ }
+
+ /**
+ * 通过id查询站内信息
+ * @param id id
+ * @return R
+ */
+ @Operation(summary = "通过id查询", description = "通过id查询")
+ @GetMapping("/{id}")
+ @PreAuthorize("@pms.hasPermission('sys_message_view')")
+ public R getById(@PathVariable("id") Long id) {
+ return R.ok(sysMessageService.getMessage(id));
+ }
+
+ /**
+ * 新增站内信息
+ * @param sysMessage 站内信息
+ * @return R
+ */
+ @Operation(summary = "新增站内信息", description = "新增站内信息")
+ @SysLog("新增站内信息")
+ @PostMapping
+ @PreAuthorize("@pms.hasPermission('sys_message_add')")
+ public R save(@RequestBody SysMessageVO sysMessage) {
+ return R.ok(sysMessageService.saveOrUpdateMessage(sysMessage));
+ }
+
+ /**
+ * 修改站内信息
+ * @param sysMessage 站内信息
+ * @return R
+ */
+ @Operation(summary = "修改站内信息", description = "修改站内信息")
+ @SysLog("修改站内信息")
+ @PutMapping
+ @PreAuthorize("@pms.hasPermission('sys_message_edit')")
+ public R updateById(@RequestBody SysMessageVO sysMessage) {
+ return R.ok(sysMessageService.saveOrUpdateMessage(sysMessage));
+ }
+
+ /**
+ * 通过id删除站内信息
+ * @param ids id列表
+ * @return R
+ */
+ @Operation(summary = "通过id删除站内信息", description = "通过id删除站内信息")
+ @SysLog("通过id删除站内信息")
+ @DeleteMapping
+ @PreAuthorize("@pms.hasPermission('sys_message_del')")
+ public R removeById(@RequestBody Long[] ids) {
+ return R.ok(sysMessageService.removeBatchByIds(CollUtil.toList(ids)));
+ }
+
+ /**
+ * 导出excel 表格
+ * @param sysMessage 查询条件
+ * @param ids 导出指定ID
+ * @return excel 文件流
+ */
+ @ResponseExcel
+ @GetMapping("/export")
+ @PreAuthorize("@pms.hasPermission('sys_message_export')")
+ public List export(SysMessageEntity sysMessage, Long[] ids) {
+ return sysMessageService
+ .list(Wrappers.lambdaQuery(sysMessage).in(ArrayUtil.isNotEmpty(ids), SysMessageEntity::getId, ids));
+ }
+
+ /**
+ * 发送站内信息
+ * @param id 站内信息
+ * @return R
+ */
+ @Operation(summary = "发送站内信息", description = "发送站内信息")
+ @SysLog("发送站内信息")
+ @PostMapping("/send")
+ @PreAuthorize("@pms.hasPermission('sys_message_add')")
+ public R send(Long id) {
+ return R.ok(sysMessageService.sendMessage(id));
+ }
+
+ /**
+ * 读取站内信息
+ * @param id 站内信息
+ * @return R
+ */
+ @Operation(summary = "读取站内信息", description = "读取站内信息")
+ @SysLog("发送站内信息")
+ @PostMapping("/read")
+ public R read(Long id) {
+ return R.ok(sysMessageService.readMessage(id));
+ }
+
+ /**
+ * 查询用户公告
+ * @param page 分页条件
+ * @param sysMessage 查询条件
+ * @return list
+ */
+ @Operation(summary = "查询用户信", description = "查询用户信")
+ @GetMapping("/user/page")
+ public R getUserMessageList(@ParameterObject Page page, SysMessageVO sysMessage) {
+ return R.ok(sysMessageService.pageUserMessage(page, sysMessage));
+ }
+
+ /**
+ * 查询信息阅读列表
+ * @return list
+ */
+ @Operation(summary = "查询用户阅读情况", description = "查询用户阅读情况")
+ @GetMapping("/user/read/page")
+ public R getUserMessageList(@ParameterObject Page page, @ParameterObject Long messageId,
+ @ParameterObject @RequestParam(required = false) String name) {
+ return R.ok(sysMessageService.pageUserRead(page, messageId, name));
+ }
+
+}
diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/mapper/SysMessageMapper.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/mapper/SysMessageMapper.java
new file mode 100644
index 000000000..81811acde
--- /dev/null
+++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/mapper/SysMessageMapper.java
@@ -0,0 +1,10 @@
+package com.pig4cloud.pigx.admin.mapper;
+
+import com.pig4cloud.pigx.admin.api.entity.SysMessageEntity;
+import com.pig4cloud.pigx.common.data.datascope.PigxBaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface SysMessageMapper extends PigxBaseMapper {
+
+}
diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/mapper/SysMessageRelationMapper.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/mapper/SysMessageRelationMapper.java
new file mode 100644
index 000000000..7a0640c70
--- /dev/null
+++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/mapper/SysMessageRelationMapper.java
@@ -0,0 +1,10 @@
+package com.pig4cloud.pigx.admin.mapper;
+
+import com.pig4cloud.pigx.admin.api.entity.SysMessageRelationEntity;
+import com.pig4cloud.pigx.common.data.datascope.PigxBaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface SysMessageRelationMapper extends PigxBaseMapper {
+
+}
diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/SysMessageService.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/SysMessageService.java
new file mode 100644
index 000000000..886610514
--- /dev/null
+++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/SysMessageService.java
@@ -0,0 +1,54 @@
+package com.pig4cloud.pigx.admin.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.pig4cloud.pigx.admin.api.entity.SysMessageEntity;
+import com.pig4cloud.pigx.admin.api.vo.SysMessageVO;
+
+public interface SysMessageService extends IService {
+
+ /**
+ * 发送信息
+ * @param id 消息ID
+ * @return true/false
+ */
+ Boolean sendMessage(Long id);
+
+ /**
+ * 保存
+ * @param sysMessage 消息
+ * @return true/false
+ */
+ Boolean saveOrUpdateMessage(SysMessageVO sysMessage);
+
+ /**
+ * 获取用户的信息列表
+ * @return list
+ */
+ IPage pageUserMessage(Page page, SysMessageVO sysMessage);
+
+ /**
+ * 读取信息
+ * @param id id
+ * @return true/false
+ */
+ Boolean readMessage(Long id);
+
+ /**
+ * 获取信息
+ * @param id id
+ * @return messageVO
+ */
+ SysMessageVO getMessage(Long id);
+
+ /**
+ * 查询用户阅读情况
+ * @param page 分页
+ * @param messageId 消息ID
+ * @param name 姓名
+ * @return page
+ */
+ Page pageUserRead(Page page, Long messageId, String name);
+
+}
diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysMessageServiceImpl.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysMessageServiceImpl.java
new file mode 100644
index 000000000..2671d115d
--- /dev/null
+++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysMessageServiceImpl.java
@@ -0,0 +1,194 @@
+package com.pig4cloud.pigx.admin.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.github.yulichang.wrapper.MPJLambdaWrapper;
+import com.pig4cloud.pigx.admin.api.entity.SysMessageEntity;
+import com.pig4cloud.pigx.admin.api.entity.SysMessageRelationEntity;
+import com.pig4cloud.pigx.admin.api.entity.SysUser;
+import com.pig4cloud.pigx.admin.api.vo.OrgTreeVO;
+import com.pig4cloud.pigx.admin.api.vo.SysMessageReadVO;
+import com.pig4cloud.pigx.admin.api.vo.SysMessageVO;
+import com.pig4cloud.pigx.admin.mapper.SysMessageMapper;
+import com.pig4cloud.pigx.admin.mapper.SysMessageRelationMapper;
+import com.pig4cloud.pigx.admin.mapper.SysUserMapper;
+import com.pig4cloud.pigx.admin.service.SysMessageService;
+import com.pig4cloud.pigx.common.core.constant.enums.YesNoEnum;
+import com.pig4cloud.pigx.common.security.util.SecurityUtils;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * 站内信息
+ *
+ * @author pig
+ * @date 2023-10-25 13:37:25
+ */
+@Service
+@RequiredArgsConstructor
+public class SysMessageServiceImpl extends ServiceImpl
+ implements SysMessageService {
+
+ private final SysMessageRelationMapper relationMapper;
+
+ private final SysUserMapper userMapper;
+
+ /**
+ * 发送信息
+ * @param id id
+ * @return true/false
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Boolean sendMessage(Long id) {
+ // 更新信息状态
+ SysMessageEntity sysMessage = new SysMessageEntity();
+ sysMessage.setSendFlag(YesNoEnum.YES.getCode());
+ baseMapper.update(sysMessage, Wrappers.lambdaQuery().eq(SysMessageEntity::getId, id));
+ return Boolean.TRUE;
+ }
+
+ /**
+ * 保存消息及其关联关系
+ * @param sysMessage 消息对象
+ * @return 是否保存成功
+ */
+ @Transactional(rollbackFor = Exception.class)
+ public Boolean saveOrUpdateMessage(SysMessageVO sysMessage) {
+ SysMessageEntity messageEntity = new SysMessageEntity();
+ BeanUtils.copyProperties(sysMessage, messageEntity);
+
+ if (Objects.isNull(sysMessage.getId())) {
+ baseMapper.insert(messageEntity);
+ }
+ else {
+ baseMapper.updateById(sysMessage);
+ }
+
+ // 删除原有用户
+ relationMapper.delete(Wrappers.lambdaQuery()
+ .eq(SysMessageRelationEntity::getMsgId, messageEntity.getId()));
+
+ List userList = sysMessage.getUserList();
+ if (CollUtil.isNotEmpty(userList)) {
+ userList.forEach(user -> {
+ SysMessageRelationEntity relationEntity = new SysMessageRelationEntity();
+ relationEntity.setMsgId(messageEntity.getId());
+ relationEntity.setUserId(user.getId());
+ relationMapper.insert(relationEntity);
+ });
+ }
+ else {
+ userMapper.selectList(Wrappers.emptyWrapper()).stream().map(SysUser::getUserId).forEach(userId -> {
+ SysMessageRelationEntity relationEntity = new SysMessageRelationEntity();
+ relationEntity.setMsgId(messageEntity.getId());
+ relationEntity.setUserId(userId);
+ relationMapper.insert(relationEntity);
+ });
+ }
+ return Boolean.TRUE;
+ }
+
+ /**
+ * 获取用户的信息列表
+ * @return list
+ */
+ @Override
+ public IPage pageUserMessage(Page page, SysMessageVO sysMessage) {
+ MPJLambdaWrapper wrapper = new MPJLambdaWrapper()
+ .selectAll(SysMessageEntity.class)
+ .select(SysMessageRelationEntity::getReadFlag)
+ .leftJoin(SysMessageRelationEntity.class, SysMessageRelationEntity::getMsgId, SysMessageEntity::getId)
+ .eq(SysMessageRelationEntity::getUserId, SecurityUtils.getUser().getId())
+ .eq(SysMessageEntity::getSendFlag, YesNoEnum.YES.getCode())
+ .eq(StrUtil.isNotBlank(sysMessage.getCategory()), SysMessageEntity::getCategory, sysMessage.getCategory())
+ .eq(StrUtil.isNotBlank(sysMessage.getReadFlag()), SysMessageRelationEntity::getReadFlag,
+ sysMessage.getReadFlag())
+ .orderByDesc(SysMessageEntity::getSort)
+ .orderByDesc(SysMessageEntity::getCreateTime);
+ return baseMapper.selectJoinPage(page, SysMessageVO.class, wrapper);
+ }
+
+ /**
+ * 读取信息
+ * @param id id
+ * @return true/false
+ */
+ @Override
+ public Boolean readMessage(Long id) {
+ SysMessageRelationEntity relationEntity = new SysMessageRelationEntity();
+ relationEntity.setReadFlag(YesNoEnum.YES.getCode());
+ relationMapper.update(relationEntity,
+ Wrappers.lambdaQuery()
+ .eq(SysMessageRelationEntity::getMsgId, id)
+ .eq(SysMessageRelationEntity::getUserId, SecurityUtils.getUser().getId()));
+ return Boolean.TRUE;
+ }
+
+ /**
+ * 获取信息
+ * @param id id
+ * @return messageVO
+ */
+ @Override
+ public SysMessageVO getMessage(Long id) {
+ SysMessageEntity messageEntity = baseMapper.selectById(id);
+ SysMessageVO SysMessageVO = new SysMessageVO();
+ BeanUtils.copyProperties(messageEntity, SysMessageVO);
+
+ // 全体通知
+ if (messageEntity.getAllFlag().equals(YesNoEnum.YES.getCode())) {
+ return SysMessageVO;
+ }
+ List userIdList = relationMapper
+ .selectList(Wrappers.lambdaQuery().eq(SysMessageRelationEntity::getMsgId, id))
+ .stream()
+ .map(SysMessageRelationEntity::getUserId)
+ .collect(Collectors.toList());
+
+ if (CollUtil.isNotEmpty(userIdList)) {
+ List orgNodeUserVoList = userMapper.selectBatchIds(userIdList).stream().map(user -> {
+ OrgTreeVO nodeUserVo = new OrgTreeVO();
+ nodeUserVo.setId(user.getUserId());
+ nodeUserVo.setAvatar(user.getAvatar());
+ nodeUserVo.setName(user.getName());
+ return nodeUserVo;
+ }).collect(Collectors.toList());
+
+ SysMessageVO.setUserList(orgNodeUserVoList);
+ }
+
+ return SysMessageVO;
+ }
+
+ /**
+ * 查询用户阅读情况
+ * @param page 分页
+ * @param messageId 消息ID
+ * @param name 姓名
+ * @return page
+ */
+ @Override
+ public Page pageUserRead(Page page, Long messageId, String name) {
+ MPJLambdaWrapper wrapper = new MPJLambdaWrapper()
+ .selectAll(SysMessageRelationEntity.class)
+ .select(SysUser::getUsername, SysUser::getName, SysUser::getUserId)
+ .select(SysMessageEntity::getTitle)
+ .leftJoin(SysUser.class, SysUser::getUserId, SysMessageRelationEntity::getUserId)
+ .leftJoin(SysMessageEntity.class, SysMessageEntity::getId, SysMessageRelationEntity::getMsgId)
+ .eq(SysMessageRelationEntity::getMsgId, messageId)
+ .like(StrUtil.isNotBlank(name), SysUser::getName, name);
+ return relationMapper.selectJoinPage(page, SysMessageReadVO.class, wrapper);
+ }
+
+}
diff --git a/pigx-upms/pigx-upms-biz/src/main/resources/mapper/SysMessageMapper.xml b/pigx-upms/pigx-upms-biz/src/main/resources/mapper/SysMessageMapper.xml
new file mode 100644
index 000000000..df0be3955
--- /dev/null
+++ b/pigx-upms/pigx-upms-biz/src/main/resources/mapper/SysMessageMapper.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/pigx-upms/pigx-upms-biz/src/main/resources/mapper/SysMessageRelationMapper.xml b/pigx-upms/pigx-upms-biz/src/main/resources/mapper/SysMessageRelationMapper.xml
new file mode 100644
index 000000000..82655e1c6
--- /dev/null
+++ b/pigx-upms/pigx-upms-biz/src/main/resources/mapper/SysMessageRelationMapper.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+