# 通知公告模块(MVP 实现对齐版) ## 1. 目标与定位 - 面向校内用户的通知/公告发布与阅读,支持富文本、附件、置顶、有效期与阅读回执。 - 可见范围支持:全员、按角色、按部门、按岗位(与 RuoYi 系统管理的角色/部门/岗位表对齐)。 - 与 RuoYi 内置 sys_notice 解耦实现,前端富文本编辑复用 RuoYi 现有富文本组件(TinyMCE/富文本编辑器封装)。 ## 2. 角色与权限 - user(普通用户):公告列表与详情、附件下载、已读未读标识。 - staff(学生工作者):新增/编辑/删除自身公告、发布/撤回/置顶自身公告;配置自身公告的可见范围(全员/角色/部门/岗位)。 - major_lead(专业负责人):与普通用户一样 - librarian(图书管理员):与普通用户一样 - admin/super_admin:公告全量的增删改查与发布、置顶、撤回。 后端权限标识(与前端按钮一致): - `manage:notice:list` `manage:notice:get` - `manage:notice:add` `manage:notice:edit` `manage:notice:remove` - `manage:notice:publish` `manage:notice:pin` ## 3. 功能范围(MVP) - 发布端: - 新增/编辑/删除(草稿/发布/撤回/过期) - 发布/撤回;置顶/取消置顶(置顶时间排序,最新置顶在顶部,不限数量) - 可见范围:全员 或 自定义(可多选:角色/部门/岗位,任一匹配即可见) - 附件:通过 OSS 上传获取 URL,随公告保存 - 有效期:到期后列表默认不显示,但链接仍可访问并明显标注“已过期” - 富文本编辑复用 RuoYi 前端组件 - 字段展示:发布时间、最后更新时间、编辑次数 - 阅读端: - 列表分页(置顶优先),关键词搜索(标题) - 展示已读/未读状态;进入详情自动且幂等记录阅读回执(同一用户仅首次计数) - 筛选:状态(含“全部=-1”)、是否包含过期、已读/未读 - 排序:按发布时间/更新时间/过期时间(升序/降序),置顶始终优先 - 详情展示附件并可下载 - 统计(MVP): - 阅读计数(打开详情即计数) 非 MVP(后续版本): - 审批流、定时发布、站内信/推送提醒、富文本内联图片增强、需要“确认已读”的回执、按专业/用户的更细粒度范围(已预留扩展)。 ## 4. 数据模型(概览) - `tb_notice`:公告主体(富文本、状态、置顶、有效期、可见范围是否全员、发布与编辑元数据、统计计数、审计字段) - `tb_notice_scope`:可见范围条目(scope_type=role/dept/post;ref_id 对应 sys_role/sys_dept/sys_post) - `tb_notice_attachment`:附件(名称、URL、类型、大小、排序) - `tb_notice_read`:阅读回执(用户是否已读、时间与审计字段) 可见范围判定规则: - 若 `visible_all=1`,所有用户可见;否则用户满足以下任一条件即可见: - 其任一角色在 `tb_notice_scope(scope_type=role)` - 其所属部门在 `tb_notice_scope(scope_type=dept)` - 其任一岗位在 `tb_notice_scope(scope_type=post)` ## 5. 状态与流转 - status:0 草稿 → 1 已发布 →(2 撤回)/(3 已过期) - 已过期的判定:`now() > expire_time` 视为“过期”,列表默认不显示;可选 `includeExpired=true` 显示;详情可访问并显示“已过期”。 - 已发布可直接编辑(允许小修改):更新 `update_time` 且 `edit_count+1`。 - 撤回会自动取消置顶(`pinned=0, pinned_time=null`)。 ## 6. 关键业务规则 - 置顶:仅对“已发布”生效;按 `pinned_time` 倒序;不设上限。 - 发布幂等:重复发布同一公告直接成功返回(不重复操作)。 - 可见范围仅影响“访问控制与列表过滤”,修改范围不改变历史阅读回执。 - 删除为软删(`del_flag`),阅读回执与附件保留(不物理删)。 - 编辑附件(MVP):覆盖式保存(清空后重建)。若需“归档不删除附件”,可将“删除附件”改为软删(`del_flag=2`)并在查询中过滤 `del_flag='0'`(可选增强)。 - 附件白名单与大小限制:pdf/docx/xlsx/png/jpg/zip;单文件≤20MB(与网关/OSS一致)。 ## 7. 接口草案(对齐 RuoYi 风格) - GET `/manage/notice/list` 权限 `manage:notice:list` - 入参:分页、`keyword`、`status?`(-1=全部)、`pinned?`、`includeExpired?`(bool,默认false)、`read?`(true/false)、`orderBy?`(publishTime|updateTime|expireTime)、`orderDir?`(asc|desc) - 出参:含每条记录 `read`(当前用户是否已读)、`expired`(是否过期)、`pinned`、`publishTime`、`updateTime`、`expireTime`、`editCount`、`readCount` - GET `/manage/notice/{id}` 权限 `manage:notice:get`(进入详情即记录回执) - POST `/manage/notice` 权限 `manage:notice:add`(含附件与可见范围列表) - PUT `/manage/notice` 权限 `manage:notice:edit` - DELETE `/manage/notice/{ids}` 权限 `manage:notice:remove` - PUT `/manage/notice/{id}/publish` 权限 `manage:notice:publish` - PUT `/manage/notice/{id}/retract` 权限 `manage:notice:publish` - 行为:撤回同时自动取消置顶 - PUT `/manage/notice/{id}/pin` 权限 `manage:notice:pin`(Body: `{ "pinned": true|false }`) ## 8. 查询与性能建议 - 列表过滤: - `visible_all=1` 直接可见;否则使用 `EXISTS` 子查询判断角色/部门/岗位三类任一匹配 - 置顶优先排序:`pinned DESC, pinned_time DESC, {orderBy} {orderDir}`(默认 `publish_time DESC`) - 索引: - `tb_notice(status, pinned, pinned_time, publish_time)` - `tb_notice(expire_time)`、`tb_notice(publisher_id)`、`tb_notice(title)` - `tb_notice_scope(notice_id)`、`tb_notice_scope(scope_type, ref_id)` - `tb_notice_read(notice_id, user_id)` 唯一约束 ## 9. 边界与异常 - 过期:详情可访问并展示“已过期”;列表默认不出;支持 `includeExpired=true` 查看。 - 非管理员“全部(-1)”视角:仅返回“所有已发布 + 本人草稿/撤回”。 - 并发:最简实现,更新时统一自增 `edit_count` 与 `update_time`;写操作加事务。 - 参数校验:标题必填≤200;内容富文本必填;有效期 `expire_time > publish_time`。 ## 10. 与 RuoYi 体系的结合 - 可见范围外键不做物理外键,仅以 `ref_id` 逻辑约束到 `sys_role.role_id` / `sys_dept.dept_id` / `sys_post.post_id`。 - 富文本:复用前端富文本组件;后端存储 `content_html`(MEDIUMTEXT)。 - 用户信息:`publisher_id` 与回执 `user_id` 对应 `sys_user.user_id`。 (本文件为冻结版需求;若有修改将以变更记录方式更新。)