[开发]FlintHub 社区治理模块(举报中心 + 通知联动 + 小黑屋)开发计划

👑Lv.11 元老 🌞 骨干会员
2026-10-24 00:21:40

本文由 FlintHub 开发文档归档发布。原始文档日期见标题前缀,来源:暂存20260913/插件开发计划.md。

FlintHub 社区治理模块(举报中心 + 通知联动 + 小黑屋)开发计划

插件名:mod_system

目标:用户举报内容 → 后台治理(删除/封禁/驳回)→ 小黑屋封禁 → 三方通知

本文档为开发计划,仅规划,不落地代码。待你确认后启动实施。


一、系统机制认知(基于现状源码)

在动手前,我已核对 WWW 当前这套源码(非 xiunox)的关键机制:

机制现状对本插件的影响
插件系统app/Helpers/Plugin.php,插件目录 plugins/{name}/,plugin.json 声明 hooks按 plugin.json 注册的钩子挂载逻辑,Plugin.php 提供 activate()/deactivate()/uninstall()
插件独立库Plugin::db($name) 返回 plugins/{name}/data/{name}.sqlite,自动生成 .htaccess/web.config 防护举报/封禁/日志表放插件独立库,卸载即清库
建表Plugin::ensureSchema($name, $ddl) 幂等 DDL用 CREATE TABLE IF NOT EXISTS
前台路由index.php 中 Plugin::hook('route_register', ['router'=>$router])注册举报/通知前台路由
后台路由/admin 分组内 Plugin::hook('admin_route_register', ['router'=>$r])注册后台治理/小黑屋路由
后台鉴权后台控制器继承 app\Controllers\Admin\BaseController(自动 Auth::isAdmin() + 二次验证)本插件后台控制器直接继承它
全局拦截点Plugin::hook('route_before_dispatch')(index.php 分发前)用于封禁用户全局动作拦截
用户users.group_id;user_groups 默认 1普通/2VIP/3版主/4管理员;role='admin' && group_id==4 才是管理员封禁=记入小黑屋表+迁入封禁组(组 ID 你在后台建,作为配置项,不硬编码)
认证Auth::isLoggedIn() / isAdmin() / requireAdmin();Controller::requireLogin()前台按钮仅登录用户看,后台用 BaseController 保护
登录流AuthController::login(),成功后 auth_login_after 钩子(登录后)需在写入 Session 前拦截,新增 auth_login_check 前置钩子
帖子存储SplitDB 分片:topic(桶) + topic_index(main_index);Thread::softDelete($id) 软删进回收站删除内容一律调 Thread::softDelete(),内容进已存在的 回收站
回复posts(退役表)/reply(桶) + reply_index;Post 模型有删除逻辑回复删除复用核心 Post 删除逻辑
博客/评论blogs、blog_comments、BlogController博客删除复用核心删除逻辑
用户组迁移User::updateByAdmin() 可改 group_id封禁/解封改 group_id
设置app\Helpers\Settings::get($key, $default)(settings 表)全局配置存 settings 表(前缀 modsystem_,与 seo 插件同模式)
通知中心系统无独立"通知中心",仅私信 messages 表(收件箱带未读角标)通知走插件自带轻量通知表 + 导航钩子显示红点(详见 §九)
前端内置 mn- CSS、Alpine.js、htmx,禁止第三方框架弹窗/反馈用 Alpine + htmx + mn- 样式
多语言plugins/{name}/lang/{zh,en,zh_tw}.php 自动合并三语种键值对
定时任务有 cron_trigger.php、cli/worker.php自动解封用"请求时懒检测"(最简单,无需定时任务)
页面缓存data/runtime/pages/*.html 游客列表缓存,PageCache::invalidate()删除内容后需失效,保证见效果


二、插件目录结构

plugins/mod_system/
├── plugin.json              # 声明钩子
├── Plugin.php               # 激活/停用/卸载、配置读写、封禁服务
├── FrontController.php      # 前台:举报提交、通知中心
├── AdminController.php      # 后台:举报列表/处理、小黑屋、配置
├── hook/
│   ├── route_register.php            # 前台路由
│   ├── admin_route_register.php      # 后台路由
│   ├── admin_sidebar_links.php       # 后台侧边栏入口
│   ├── route_before_dispatch.php     # 封禁全局动作拦截
│   ├── auth_login_check.php          # 登录拦截(封禁用户不得登录)
│   ├── nav_user_menu_items.php       # 前台导航"举报通知红点"
│   ├── thread_operation_after.php    # 帖子详情主帖操作区 → 举报按钮
│   ├── post_operation_after.php      # 帖子详情回复楼层操作区 → 举报按钮
│   ├── blog_detail_operation_after.php # 博客详情正文操作区 → 举报按钮
│   ├── blog_comment_operation_after.php # 博客详情评论操作区 → 举报按钮
│   └── profile_user_card_after.php   # 个人主页用户卡片 → 举报按钮
├── views/
│   ├── admin_list.php        # 举报列表(分页+筛选+批量+预警高亮)
│   ├── admin_ban.php         # 小黑屋列表(解封入口)
│   ├── admin_config.php      # 全局配置页
│   ├── report_modal.php      # 前台举报弹窗(被 htmx 拉取 or 内联)
│   └── notifications.php     # 前台通知中心
├── assets/
│   └── style.css             # 插件专属样式(mn- 基础上微量扩展)
├── lang/
│   ├── zh.php  ├── en.php  └── zh_tw.php
└── data/                     # 运行时自动生成 .htaccess/web.config + mod_system.sqlite


三、数据表设计(插件独立库 mod_system.sqlite)

1. mod_reports(举报记录)

列类型说明
idINTEGER PK
reporter_idINTEGER举报人(匿名举报仍记 ID,仅展示时脱敏)
target_typeTEXTthread / post / blog / blog_comment / user
target_idINTEGER目标内容 ID
target_uidINTEGER被举报用户 ID(预存,防内容删除后可查)
categoryTEXT分类:spam/porn/illegal/attack/flood/fake/other
noteTEXT补充说明,≤200 字
is_anonymousINTEGER1=匿名举报
ipTEXT举报 IP(辅助防刷)
statusINTEGER0 待处理 / 1 已处理 / 2 已驳回
handle_actionTEXTdismiss/delete/ban/delete_ban
handler_idINTEGER处理人
handled_atTEXT
created_atTEXT

  • 索引:(target_type, target_id)、(status)、(reporter_id, created_at)

2. mod_bans(小黑屋)

列类型说明
idINTEGER PK
user_idINTEGER被封禁用户
reasonTEXT封禁原因
banned_byINTEGER处理人
banned_atTEXT
expires_atTEXT NULL空=永久封禁;否则限时解封时间
original_group_idINTEGER封禁前用户组,解封恢复用
statusINTEGER1 生效 / 0 已解封
unbanned_byINTEGER解封人
unbanned_atTEXT

3. mod_logs(处理日志,可追溯)

列类型说明
idINTEGER PK
report_idINTEGER关联举报
user_idINTEGER处理人
target_uidINTEGER被处理用户
actionTEXTdismiss/delete/ban/delete_ban
detailTEXT摘要
created_atTEXT

4. mod_notifications(插件通知中心)

列类型说明
idINTEGER PK
to_uidINTEGER接收者(被举报人/管理员/举报人)
typeTEXTreport_new / auto_audit / report_result / ban_penalty
titleTEXT
contentTEXT
urlTEXT跳转链接
is_readINTEGER0 未读
created_atTEXT


四、全局配置项(settings 表,前缀 modsystem_)

键默认说明
modsystem_auto_audit_count3同一内容被举报 N 次后台自动标红预警
modsystem_daily_limit5每用户每日最多举报次数
modsystem_cooldown300同一用户对同一内容举报冷却秒数
modsystem_notify_enabled1通知中心联动开关(0=关闭不发通知)
modsystem_ban_group_id``封禁用户组 ID(你在后台建好小组后填,不硬编码)
modsystem_ban_days7小黑屋默认"封禁天数"(0 或空=永久,可在小黑屋列表逐条改)
modsystem_moderator_group_ids``(可选,预留)可处理举报的高管用户组 ID 多选框(默认空=仅管理员)

配置页展示全部 7 项,保存后 Settings::clearCache()。


五、前台用户功能(举报流程)

举报入口(共五类目标)

  • 帖子详情主帖:thread_operation_after 钩子在主帖操作区(show.php 编辑/删除按钮附近)注入"举报"按钮 → target_type=thread
  • 帖子详情回复楼层:post_operation_after 在每个回复操作区注入"举报"按钮 → target_type=post
  • 博客详情正文:blog_detail_operation_after 注入"举报"按钮 → target_type=blog
  • 博客详情评论文楼层:每个评论操作区注入"举报"按钮 → target_type=blog_comment(复用 post_operation_after 同一套弹窗/提交逻辑,仅 target_type 不同)
  • 个人主页:profile_user_card_after 在用户卡片注入"举报用户"按钮 → target_type=user
  • 仅登录用户展示(Auth::isLoggedIn())
  • 前端用 htmx 拉取弹窗 HTML,Alpine 控制开关

举报弹窗表单

  • 分类单选(7 种):spam垃圾广告 / porn色情低俗 / illegal违法违规 / attack人身攻击 / flood恶意刷屏 / fake虚假信息 / other其他
  • 补充说明:textarea 选填,maxlength=200
  • 勾选"匿名举报"(默认不勾)

匿名举报实现(重要:前端脱敏 ≠ 后端隐藏)

  • 数据库始终存 reporter_id(mod_reports.reporter_id + mod_logs 都不为空),后台管理员列表/详情可查真实举报人
  • is_anonymous=1 只影响对外展示:后台列表对"举报人"列显示"匿名",通知/邮件不携带举报人身份
  • 后端永不因匿名而减少防刷校验:cooldown / daily_limit / IP 限流对匿名举报者照样生效,防止借匿名校验绕过

提交限制(FrontController::submit 内校验)

  1. 未登录 → 拒绝
  2. 不能举报自己
  3. Cooldown:同用户对同目标(target_type+target_id)在 cooldown 秒内重复 → "您已举报过该内容,请稍后再试"
  4. 每日 daily_limit 上限(按 reporter_id 当日次数)→ "今日举报次数已达上限,请明日再试"
  5. 目标必须存在(thread/post/blog/blog_comment/user 各自校验)
  6. 同一用户对同一目标仅计一条待处理举报(重复提交合并;不同用户累计才触发预警)

无感反馈

  • 成功 → "举报成功,感谢您的监督"(htmx 局部提示)
  • 匿名与否不影响任何限制:cooldown/daily_limit 按真实 reporter_id 计,匿名只是展示层脱敏

六、后台管理功能(治理流程)

继承 app\Controllers\Admin\BaseController,天然具备管理员权限保护

1. 举报列表 GET /admin/mod-system/reports

  • 字段:内容摘要、被举报人、举报分类、举报人(匿名则显示"匿名")、提交时间、状态、处理结果
  • 筛选:全部 / 待处理 / 已处理 / 已驳回(?status=)
  • 预警高亮:目标累计举报次数 ≥ auto_audit_count 时该行背景高亮(admin.css 扩展类)
  • 分页:?page=,per_page 默认 20

2. 单条处理 POST /admin/mod-system/reports/{id}/handle

  • dismiss 驳回:标记已驳回,不惩罚
  • delete 删除:调核心软删/删除逻辑删帖/回复/博客/博客评论,内容进回收站
  • ban 封禁:目标用户迁入封禁组 + 记小黑屋(可带封禁天数)
  • delete_ban 删除+封禁:先删内容再封禁用户
  • 每次处理写 mod_logs(处理人/时间/结果)
  • 处理表单带"封禁天数"输入框(ban_days,0/空=永久),ACTION=ban/delete_ban 时生效

3. 批量处理 POST /admin/mod-system/reports/batch

  • 勾选多条 → 批量 驳回 / 删除 / 封禁
  • 合并通知(同目标只封一次,去重)

4. 处理日志

  • 后台单独 tab 查看 mod_logs,或列表内联展示最近动作

七、小黑屋(封禁模块)GET/POST /admin/mod-system/bans

数据逻辑

  • mod_bans 独立表:用户 ID、原因、封禁时间、解封时间、原用户组
  • 封禁动作:INSERT mod_bans + UPDATE users SET group_id = :ban_group_id(ban_group_id 为空则仅记表不迁组,由管理员手动设置)
  • 封禁方式:永久(expires_at = NULL)或限时(expires_at = banned_at + N 天)

小黑屋列表(后台)

  • 列:用户名、封禁原因、封禁人、封禁时间、解封时间、状态
  • 新建/编辑封禁提供"封禁天数"输入框(默认取 modsystem_ban_days,0/空=永久)→ 对轻微违规可"关几天"
  • 状态展示剩余解封时间;已解封行置灰

封禁判断(Plugin::isBanned($uid))

  • 查 mod_bans.status=1 且(expires_at 为空 或 expires_at > now)
  • 懒解封:若 expires_at <= now,顺手执行自动解封(删除记录 + 恢复 original_group_id),并返回未封禁

拦截机制

  1. 登录拦截:auth_login_check 钩子(放在 Session 建立前)→ 封禁用户提示"您的账号已被封禁",拒绝登录
  2. 操作拦截(力度 = 只拦写操作):route_before_dispatch 全局钩子
  • 只拦截写操作:发帖、回帖、发博客、博客评论、回复、上传(按 POST 方法 + 目标路由白名单判定)
  • 读操作一律放行:看帖、看博客、看通知、看个人主页、浏览列表 → 被封禁者仍能"看自己是否解封/看通知",保留申诉与自查能力
  • 拦截时返回明确提示(如"您的账号已被封禁,无法执行此操作")
  1. 内容冻结:仅对当前处于封禁状态的用户内容加"该用户已被封禁"提示(数据层不改,仅展示)。解封后提示自动消失;被举报但未封禁的内容不加任何提示(避免误伤/虚假负面形象)

解封机制

  • 自动:请求时懒检测到期自动恢复(无需定时任务)
  • 手动:后台"小黑屋列表"点"解除封禁" → 删 mod_bans 记录 + 恢复 original_group_id
  • 封禁生效(新增/修改)后统一 PageCache::invalidate():即使用户内容未删除仅迁组,也强制失效游客列表缓存,确保前台"该用户已被封禁"提示即时一致(简单粗暴但保证一致性)

八、通知中心联动(mod_notifications 表)

系统无独立通知中心,故插件自带轻量通知表,并在前台导航钩子显示未读红点。

已确认:不复用现有 messages 私信表(收件箱 JOIN 依赖 sender_id>0,系统通知 sender 为 0 会丢显示、造成展示错误)。

时机接收者内容
举报提交后被举报人"您的内容因【分类】被举报,请及时整改。若多次被举报,将面临封禁处理。"(不暴露举报人,匿名/实名均不暴露)
新举报产生全体管理员"有新的举报待处理"(前台通知 + 后台列表可见)
达 auto_audit_count管理员"【内容摘要】已被举报多次,请及时处理"
处理完毕举报人"您举报的内容已被处理(删除/封禁/驳回)"

  • 由 modsystem_notify_enabled 开关控制(默认开)
  • 管理员范围(已确认):通知/预警只发给 role='admin' && group_id==4;后续如需让版主等高级组处理,可通过配置页 modsystem_moderator_group_ids 多选框开放(默认空=仅管理员)
  • 前台导航通过 nav_user_menu_items / nav_plugin_links 钩子显示未读数红点,点击进 /mod-system/notifications 查看

九、权限控制

  • 后台三页全部继承 BaseController(自动管理员鉴权 + 二次验证)
  • 前台举报按钮仅登录用户可见(Auth::isLoggedIn())
  • 提交接口重复校验登录态 + CSRF
  • CSRF:所有 POST 用 Csrf::verifyOrDie($_POST['csrf'] ?? '')

十、多语言(lang/zh.php lang/en.php lang/zh_tw.php)

覆盖键:

  • plugin.mod_system.*:侧边栏导航、配置项标签、按钮
  • 举报分类 7 项
  • 提示文案:已上限 / 冷却 / 成功 / 已封禁 / 处理结果
  • 后台:列表、筛选、批量、预警、处理动作、小黑屋、解封

十一、需新增的核心钩子点(最小改动)

为在现有视图注入按钮 + 登录拦截,需在核心文件加少量钩子帧(所有逻辑都在插件内,核心仅加一行 Plugin::hook(...)):

核心文件新增钩子位置
app/Views/thread/show.phpthread_operation_after主帖操作区
app/Views/thread/show.phppost_operation_after每个回复操作区
app/Views/blog/detail.phpblog_detail_operation_after博客正文操作区
app/Views/blog/detail.phpblog_comment_operation_after每个博客评论操作区
app/Views/profile/index.phpprofile_user_card_after用户卡片
app/Controllers/AuthController.phpauth_login_check登录成功校验后、写 Session 前
app/Views/layouts/main.php复用已有 nav_user_menu_items通知红点(免加新钩子)
index.php复用已有 route_before_dispatch全局写操作拦截(免加新钩子)


十二、实施顺序

  1. 建目录骨架 + plugin.json + Plugin.php(配置读写、建表、isBanned/封禁/解封服务)
  2. 三语种 lang/
  3. 前台路由 + FrontController(举报提交 + 拦截 + 通知)
  4. 视图钩子 + 前台举报弹窗(Alpine + htmx)
  5. 后台路由 + AdminController(列表/处理/批量/日志)
  6. 后台视图(列表、小黑屋、配置)
  7. 通知中心(表 + 前台通知视图 + 红点)
  8. 核心钩子帧注入
  9. 联调:封禁登录拦截 / 全局动作拦截 / 删除进回收站 / PageCache 失效
  10. 验证 + 清理游客缓存

十三、决策结论(已确认)

基于你的要求,对原计划中的待确认项给出以下定论,已回填到上文各章节:

  1. 通知中心:采用插件自带 mod_notifications 表 + 导航红点方案。不复用现有 messages 私信表(系统通知 sender 为 0,收件箱 JOIN sender_id>0 会丢显示,造成展示错误)。
  2. 封禁组 ID:默认留空,由管理员在后台配置页手动填入自己建的"封禁用户组" ID(如 5)。不硬编码,后续改组长/组名无需动代码。
  3. 管理员范围:通知/预警只发给 role='admin' && group_id==4。后续如需开放给版主等高级组,通过配置页 modsystem_moderator_group_ids 多选框(默认空=仅管理员)。
  4. 内容冻结提示:只对"当前处于封禁状态"的用户内容加提示;解封后自动消失;被举报但未封禁的内容不加提示(避免误伤和虚假负面形象)。

本次调整响应的补充建议

  • 目标覆盖补上博客评论(target_type=blog_comment,新增 blog_comment_operation_after 钩子)
  • 匿名举报仅前端脱敏、后端始终存 reporter_id,且不豁免任何防刷校验
  • 小黑屋支持限时封禁天数(默认 modsystem_ban_days,可逐条改),轻微违规"关几天"
  • 全局拦截只拦写操作(POST 发帖/回帖/发博客/评论/上传),读操作全放行,保留被封禁者自查/申诉能力
  • 封禁生效后统一 PageCache::invalidate(),保证前台"该用户已被封禁"提示即时一致

确认无误后,我按计划开工实施。

轻量级、高性能、零 MySQL 依赖的PHP社区系统。
| Views 4 | Replies 0

All Replies (0)

No replies yet

Please Log in