本文由 FlintHub 开发文档归档发布。原始文档日期见标题前缀,来源:备忘md/SOSITE_V3_功能开发计划.md。
SoSite V3.0.0 — 功能开发计划
基于代码分析(2026-06-24)整理,按优先级排序。
一、代码库现状概述
| 维度 | 现状 |
|---|---|
| 路由 | 自研 Router.php,支持 get/post/any/group、参数捕获 |
| 数据库 | 自研 Database.php,支持 SQLite/MySQL 双适配,参数化查询 |
| 模型 | Model.php 基类,提供 find/all/insert/update/delete/count 基础 CRUD |
| 模板 | TemplateCompiler.php — 类 Blade 编译器 + View.php 原生 PHP 渲染,两者并存 |
| 认证 | Auth.php — Session 登录,role 字段仅有 user / admin 两档 |
| 管理员验证 | Admin/BaseController.php — 构造方法中统一拦截非管理员请求 |
| 后台路由 | /admin 分组下已有 15+ 个控制器 |
| 在线状态 | online_users 表记录最后活动时间,15 分钟超时清除 |
关键表结构
users: id, username, password, email, avatar, signature, role, post_count, points, level, theme, created_at, last_login
threads: id, category_id, user_id, title, content, view_count, reply_count, is_pinned, is_highlighted, color, reply_to_view, deleted_at, last_reply_at, created_at
posts: id, thread_id, user_id, content, deleted_at, created_at
categories: id, name, description, sort_order, created_at
online_users: user_id, last_activity二、各功能详细分析
1. 快速回复(主题底部直接回复框)
当前情况:
ThreadController::show()中已有 POST 表单回复逻辑(代码行 12-45)- 回复框在页面顶部的主帖区域,不在底部
- 缺少一个固定在底部的精简回复输入框
实施方案:
- 后端 — 复用现有 POST
/thread/{id}路由,无需新增 - 前端 — 在
app/Views/thread/show.php底部「全部回复」列表下方,添加精简回复框
- 包含:文本域 + 附件上传 + 提交按钮 + CSRF Token
- 用
content-card容器包裹,与现有风格统一
- JS — 可选的 Ctrl+Enter 快捷提交(已有
editor.js可扩展) - 涉及文件:
app/Views/thread/show.php— 追加底部回复框assets/js/editor.js— 可选优化
难度:⭐ 低
2. 帖子浏览量
当前情况:
threads表已有view_count字段(INT DEFAULT 0)Thread::incrementView($id)方法已实现ThreadController::show()中已调用$threadModel->incrementView($threadId)- 浏览量已在主题详情页展示:「浏览 X 次」
结论:✅ 已实现! 无需额外开发。若需增强,可考虑:
- 防刷机制(同一用户短时间内重复浏览不累加)
- 论坛首页/板块列表展示浏览数字段
3. 用户组系统 — 多角色、权限控制 ⭐ 核心
当前情况:
users.role字段仅有'user'和'admin'两档Auth::isAdmin()检查$_SESSION['role'] === 'admin'Admin/BaseController.php用Auth::requireAdmin()拦截后台- 权限检查散布在各控制器中,无统一框架
实施方案(推荐方案:渐进式改造):
第一阶段:数据层
- 新建
groups表
```sql
CREATE TABLE groups (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL UNIQUE,
description VARCHAR(255),
permissions TEXT, -- JSON 格式存储权限列表
is_system TINYINT DEFAULT 0, -- 系统内置组不可删除
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
```
- 新建
group_permissions表(可选,若权限较复杂可拆) users表增加group_id字段,默认指向普通用户组- 预置 4 个系统组:
- 管理员(admin)— 全部权限
- 版主(moderator)— 版块管理权限
- 普通用户(member)— 基础权限
- 受限用户(restricted)— 只读权限
第二阶段:权限检查层
- 新建
app/Helpers/Permission.php
can($userId, $permission, $resourceId = null)— 检查用户是否有某权限- 权限定义常量:
PERM_CREATE_THREAD,PERM_EDIT_OWN,PERM_DELETE_ANY,PERM_PIN_THREAD等
Auth.php扩展方法:getUserGroup(),hasPermission()
第三阶段:后台管理
- 新增
/admin/groups路由和Admin/GroupController.php - 后台视图
admin/groups.php— 管理用户组及其权限 - 用户编辑页面增加「所属用户组」选择
第四阶段:代码迁移
- 逐步将散落的
isAdmin()检查替换为hasPermission() Admin/BaseController.php改为检查hasPermission('access_admin')
涉及文件:
database/schema_mysql.sql+schema_sqlite.sql— 新表app/Helpers/Permission.php— 新建app/Helpers/Auth.php— 扩展方法app/Core/Controller.php— 可加can()便捷方法app/Controllers/Admin/GroupController.php— 新建app/Views/admin/groups.php— 新建app/Controllers/Admin/UserController.php— 编辑页面加组选择index.php— 加路由app/Views/admin/_sidebar.php— 加导航
难度:⭐⭐⭐⭐ 高(建议分阶段实施)
4. 板块版主
当前情况:
- 无版主概念,只有管理员可以管理所有内容
- 帖子编辑/删除权限检查:
isAdmin() || 发帖人本人
实施方案:
categories表增加moderator_ids字段
```sql
ALTER TABLE categories ADD COLUMN moderator_ids TEXT; -- 存储 JSON 数组 [1, 5, 12]
```
- 新建
Category::getModerators($catId)方法 - 新建
Auth::isModerator($categoryId)方法 - 修改权限检查逻辑 — 在编辑/删除/置顶等操作时,增加版主判断
- 后台分类编辑页面 — 增加版主选择器(用户搜索 + 多选)
依赖关系: 用户组系统(功能 3)可以先做基础版,版主作为特定权限组来实现。但独立实现也可以。
涉及文件:
database/schema_mysql.sql+schema_sqlite.sql— 加字段app/Models/Category.php— 加方法app/Controllers/Admin/CategoryController.php— 编辑页版主选择app/Views/admin/categories.php— 版主选择 UIapp/Controllers/ThreadController.php— 检查增加版主app/Controllers/PostController.php— 检查增加版主
难度:⭐⭐ 中低
5. 封禁系统
当前情况:
- 无封禁功能
- 仅有简单的
requireLogin()和requireAdmin()拦截
实施方案:
- 新建
bans表
```sql
CREATE TABLE bans (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT, -- 封禁用户(可选,封禁用户时设置)
ban_type VARCHAR(20) NOT NULL, -- 'username' | 'email' | 'ip' | 'user'
ban_value VARCHAR(255) NOT NULL,-- 匹配值
reason TEXT,
created_by INT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
expires_at DATETIME, -- NULL 表示永久
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE CASCADE
);
CREATE INDEX idx_bans_type_value ON bans(ban_type, ban_value);
```
- 新建
app/Helpers/Ban.php
check($userId, $username, $email, $ip)— 检查是否被封add($data)— 添加封禁remove($id)— 解除封禁isActive($ban)— 检查封禁是否过期
- 在
app/init.php或Controller::view()中加入全局检查 — 在每次请求时验证当前用户是否被封 - 后台管理页面 — 封禁列表、添加封禁(支持输入用户名/邮箱/IP)
- 用户登录时检查 — 在
AuthController::login()中加入封禁判断
涉及文件:
database/schema_mysql.sql+schema_sqlite.sql— 新表app/Helpers/Ban.php— 新建app/Controllers/Admin/BanController.php— 新建app/Views/admin/bans.php— 新建app/Views/admin/_sidebar.php— 加导航app/Controllers/AuthController.php— 登录检查app/init.php或app/Core/Controller.php— 全局封禁检查index.php— 加路由
难度:⭐⭐⭐ 中
6. 帖子移动/合并
当前情况:
- 帖子只有软删除和永久删除功能
- 无移动分类、无合并功能
实施方案:
帖子移动
- 在
AdminThreadController中增加移动功能 - 实现逻辑:
UPDATE threads SET category_id = :newCatId WHERE id = :threadId - 批量移动:支持多选 + 目标分类选择
帖子合并
- 选择「目标主题」和「被合并的主题」
- 将被合并主题的所有回复(posts)的
thread_id改到目标主题 - 更新目标主题的
reply_count - 将被合并主题软删除
涉及文件:
app/Controllers/Admin/ThreadController.php— 加移动/合并方法app/Views/admin/threads.php— 加批量操作 UIapp/Models/Thread.php— 加moveToCategory()、mergeInto()方法app/Models/Post.php— 加moveToThread()方法
难度:⭐⭐ 中低
7. 标记全部已读
当前情况:
online_users表记录用户最后活动时间- 无"未读帖子"追踪机制
实施方案:
- 方案选型(两种):
- 轻量方案: 在
users表加last_read_at字段,对比帖子last_reply_at,晚于last_read_at的即为未读 - 完整方案: 新建
read_tracker表记录每个用户最后阅读每个板块/主题的时间
- 推荐轻量方案(渐进式):
users表加last_read_all_at DATETIME- 论坛首页/板块列表中,
threads.last_reply_at > users.last_read_all_at标记为「新帖」 - 点击「标记全部已读」→ 更新
last_read_all_at为当前时间 - 前端用高亮或 NEW 徽标标识新帖
- 后续可增强为:
- 板块级别已读追踪
- 主题级别已读追踪(配合
viewed_replies表已有功能)
涉及文件:
database/schema_mysql.sql+schema_sqlite.sql— 加字段/建表app/Models/User.php—markAllRead(),getUnreadCount()app/Controllers/ForumController.php— 未读计数传入视图app/Views/forum/index.php— 新帖标记app/Views/forum/category.php— 新帖标记index.php— 路由/forum/mark-read
难度:⭐⭐ 中低
8. 在线用户详细列表
当前情况:
online_users表有user_id, last_activitySettings::getOnlineCount()已实现,仅返回在线人数- 无用户详情列表
实施方案:
- 新建查询方法 — 获取详细在线用户列表
```sql
SELECT u.id, u.username, u.avatar, u.level, o.last_activity
FROM online_users o
JOIN users u ON o.user_id = u.id
WHERE o.last_activity >= :threshold
ORDER BY o.last_activity DESC
```
- 在
Settings或新建OnlineHelper中添加:
getOnlineUsers()— 返回在线用户列表含详细信息getOnlineCount()— 复用现有方法
- 前端展示:
- 在侧边栏或论坛底部展示在线用户列表
- 显示头像、用户名、等级徽章
- 鼠标悬停显示最后活动时间
- 在线人数统计在前面的 X 人后面可展开
涉及文件:
app/Helpers/Settings.php— 加getOnlineUsers()或新建OnlineHelper.phpapp/Views/layouts/main.php— 侧边栏在线用户列表app/Views/forum/index.php— 论坛底部在线详情assets/css/style.css— 在线用户列表样式
难度:⭐ 低
三、实施路径建议
建议分 4 个阶段推进
| 阶段 | 功能 | 预估工作量 | 说明 |
|---|---|---|---|
| Phase 1 | 快速回复 + 帖子浏览量(已ok) + 在线用户详细列表 | 小 | 快速出成果,低风险 |
| Phase 2 | 标记全部已读 + 封禁系统 + 帖子移动/合并 | 中 | 核心运维功能 |
| Phase 3 | 板块版主 | 中 | 依赖用户组的设计决策 |
| Phase 4 | 用户组系统 — 权限重构 | 大 | 根基性改造,影响面最广 |
关于帖子浏览量
经代码确认,view_count 字段 + incrementView() 方法 + 前台展示 已全部实现,无需额外开发。
依赖关系
板块版主 ──> 依赖用户组系统(推荐)或独立实现
帖子移动/合并 ──> 独立
封禁系统 ──> 独立
标记全部已读 ──> 独立
快速回复 ──> 独立
在线用户列表 ──> 独立四、就绪状态
各功能均可独立开始,无阻塞依赖。建议从 Phase 1 的快速回复或在线用户列表入手,快速看到效果。