评论系统
CarefreeCMS 内置完善的评论系统,支持多级评论、审核机制、垃圾评论过滤等功能。
功能特性
核心功能
多级评论
- 支持无限级回复
- 嵌套显示
- @提醒功能
- 引用回复
审核机制
- 人工审核
- 自动审核
- 敏感词过滤
- IP 黑名单
互动功能
- 点赞/点踩
- 举报
- 分享
- 表情包
统计功能
- 评论数量
- 评论趋势
- 热门评论
- 活跃用户
开启评论
全局设置
系统设置 → 评论设置
基本配置
// config/comment.php
return [
// 是否开启评论
'enable' => true,
// 评论审核
'need_audit' => true,
// 允许匿名评论
'allow_guest' => true,
// 嵌套层级
'max_depth' => 5,
// 评论长度
'min_length' => 10,
'max_length' => 500,
// 验证码
'need_captcha' => true,
];
文章设置
编辑文章时设置
是否允许评论:
● 是
○ 否
批量设置
1. 勾选多篇文章
2. 批量操作 → 开启/关闭评论
3. 确认
评论管理
评论列表
内容管理 → 评论管理
列表字段
评论内容 作者 文章标题 状态 时间 操作
筛选条件
状态:全部 | 待审核 | 已通过 | 已拒绝 | 垃圾评论
时间范围:今天 | 最近7天 | 最近30天 | 自定义
文章筛选:选择文章
用户筛选:选择用户
关键词搜索:评论内容
审核评论
单个审核
1. 点击"审核"按钮
2. 选择:通过 | 拒绝 | 标记为垃圾
3. 填写拒绝原因(可选)
4. 确认
批量审核
1. 勾选多条评论
2. 批量操作 → 通过/拒绝
3. 确认
自动审核
// 自动审核规则
'auto_audit' => [
// 注册用户自动通过
'registered_user' => true,
// 历史无违规用户
'trusted_user' => true,
// 无敏感词自动通过
'no_sensitive' => true,
],
回复评论
回复操作
1. 点击"回复"按钮
2. 输入回复内容
3. 可@用户
4. 发送回复
回复模板
感谢您的评论!
您的建议我们会认真考虑。
欢迎继续关注我们的更新。
删除评论
删除方式
- 移入回收站(可恢复)
- 永久删除(不可恢复)
删除原因
- 垃圾评论
- 违规内容
- 重复评论
- 无意义内容
前台展示
评论列表
<div class="comments">
<h3>评论 ({{ comment_count }})</h3>
{% for comment in comments %}
<div class="comment-item" id="comment-{{ comment.id }}">
<div class="comment-avatar">
<img src="{{ comment.user.avatar }}" alt="{{ comment.user.nickname }}">
</div>
<div class="comment-body">
<div class="comment-meta">
<span class="author">{{ comment.user.nickname }}</span>
<span class="time">{{ comment.create_time|time_ago }}</span>
<span class="floor">#{{ loop.index }}</span>
</div>
<div class="comment-content">
{{ comment.content|nl2br }}
</div>
<div class="comment-actions">
<button class="btn-like" data-id="{{ comment.id }}">
<i class="icon-thumbs-up"></i>
{{ comment.like_count }}
</button>
<button class="btn-reply" data-id="{{ comment.id }}">
<i class="icon-reply"></i>
回复
</button>
<button class="btn-report" data-id="{{ comment.id }}">
<i class="icon-flag"></i>
举报
</button>
</div>
{# 子评论 #}
{% if comment.children %}
<div class="comment-children">
{% for child in comment.children %}
{% include 'components/comment-item.html' with {'comment': child} %}
{% endfor %}
</div>
{% endif %}
</div>
</div>
{% endfor %}
{# 分页 #}
{{ pagination|raw }}
</div>
评论表单
<div class="comment-form">
<h4>发表评论</h4>
<form id="comment-form">
{% if not is_login %}
<div class="form-row">
<input type="text" name="nickname" placeholder="昵称" required>
<input type="email" name="email" placeholder="邮箱" required>
</div>
{% endif %}
<div class="form-row">
<textarea name="content"
placeholder="请输入评论内容(10-500字)"
minlength="10"
maxlength="500"
required></textarea>
</div>
<div class="form-row">
<input type="text" name="captcha" placeholder="验证码" required>
<img src="/captcha" class="captcha-img" alt="验证码">
</div>
<div class="form-actions">
<button type="submit">发表评论</button>
<span class="tip">评论将在审核后显示</span>
</div>
</form>
</div>
提交评论
const form = document.getElementById('comment-form');
form.addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(form);
const data = {
article_id: articleId,
content: formData.get('content'),
nickname: formData.get('nickname'),
email: formData.get('email'),
captcha: formData.get('captcha'),
parent_id: parentId || 0
};
try {
const res = await fetch('/api/comments', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
const result = await res.json();
if (result.code === 200) {
alert('评论成功,等待审核');
form.reset();
// 刷新评论列表
loadComments();
} else {
alert(result.message);
}
} catch (error) {
alert('评论失败,请重试');
}
});
垃圾评论过滤
敏感词过滤
配置敏感词库
// config/sensitive_words.php
return [
'敏感词1',
'敏感词2',
'广告词',
// ...
];
过滤方式
// 检测敏感词
public function checkSensitiveWords($content)
{
$words = config('sensitive_words');
foreach ($words as $word) {
if (stripos($content, $word) !== false) {
return true;
}
}
return false;
}
// 替换敏感词
public function replaceSensitiveWords($content)
{
$words = config('sensitive_words');
foreach ($words as $word) {
$content = str_ireplace($word, '***', $content);
}
return $content;
}
IP 黑名单
添加黑名单
1. 评论列表 → 选择评论
2. 点击"加入黑名单"
3. 选择封禁时长
- 7天
- 30天
- 永久
4. 填写原因
5. 确认
黑名单管理
系统设置 → IP 黑名单
黑名单检测
public function isBlacklisted($ip)
{
$blacklist = IPBlacklist::where('ip', $ip)
->where('expire_time', '>', date('Y-m-d H:i:s'))
->find();
return $blacklist !== null;
}
频率限制
限制规则
'rate_limit' => [
// 同一用户间隔时间(秒)
'user_interval' => 60,
// 同一IP间隔时间(秒)
'ip_interval' => 30,
// 每天最多评论次数
'daily_limit' => 50,
],
检测实现
public function checkRateLimit($userId, $ip)
{
$cacheKey = 'comment_limit_' . $userId;
$lastTime = Cache::get($cacheKey);
if ($lastTime && time() - $lastTime < 60) {
throw new \Exception('评论太频繁,请稍后再试');
}
Cache::set($cacheKey, time(), 3600);
}
验证码验证
开启验证码
'need_captcha' => true,
'captcha_type' => 'image', // image, sms, slider
验证实现
public function verifyCaptcha($captcha)
{
$sessionCaptcha = session('captcha');
if (empty($captcha) || strtolower($captcha) !== strtolower($sessionCaptcha)) {
throw new \Exception('验证码错误');
}
// 验证通过后清除
session('captcha', null);
return true;
}
评论通知
邮件通知
通知作者
// 有新评论时通知文章作者
public function notifyAuthor($comment, $article)
{
$author = $article->author;
if ($author->email) {
Mail::send('mail/new_comment', [
'author' => $author,
'article' => $article,
'comment' => $comment
], function($message) use ($author) {
$message->to($author->email)
->subject('您的文章有新评论');
});
}
}
通知被回复者
// 回复评论时通知原评论者
public function notifyReply($reply, $parent)
{
if ($parent->user->email) {
Mail::send('mail/comment_reply', [
'user' => $parent->user,
'reply' => $reply
], function($message) use ($parent) {
$message->to($parent->user->email)
->subject('您的评论收到回复');
});
}
}
站内通知
// 创建站内消息
Notification::create([
'user_id' => $article->user_id,
'type' => 'new_comment',
'title' => '您的文章收到新评论',
'content' => $comment->content,
'link' => '/article/' . $article->id . '#comment-' . $comment->id,
'is_read' => 0,
]);
评论统计
文章评论统计
// 获取文章评论数
$commentCount = Comment::where('article_id', $articleId)
->where('status', 1)
->count();
// 更新文章评论数
Article::where('id', $articleId)
->update(['comment_count' => $commentCount]);
用户评论统计
// 用户总评论数
$userCommentCount = Comment::where('user_id', $userId)
->where('status', 1)
->count();
// 用户今日评论数
$todayCount = Comment::where('user_id', $userId)
->whereDay('create_time', 'today')
->count();
热门评论
// 获取点赞最多的评论
$hotComments = Comment::where('status', 1)
->order('like_count', 'desc')
->limit(10)
->select();
API 接口
获取评论列表
GET /api/articles/{id}/comments?page=1
响应
{
"code": 200,
"data": {
"list": [
{
"id": 1,
"content": "写得不错!",
"user": {
"nickname": "张三",
"avatar": "https://example.com/avatar.jpg"
},
"like_count": 10,
"create_time": "2024-01-15 14:30:00",
"children": []
}
],
"total": 50
}
}
发表评论
POST /api/comments
Content-Type: application/json
{
"article_id": 1,
"content": "评论内容",
"parent_id": 0,
"captcha": "ABCD"
}
点赞评论
POST /api/comments/{id}/like
举报评论
POST /api/comments/{id}/report
Content-Type: application/json
{
"reason": "违规内容"
}
最佳实践
审核策略
信任用户
- 注册满 30 天
- 历史无违规
- 评论质量高
严格审核
- 新注册用户
- 历史有违规
- 包含链接
互动引导
鼓励评论
- 文章结尾提问
- 设置话题讨论
- 回复优质评论
- 定期评选优秀评论
处理负面评论
- 保持专业
- 耐心回复
- 合理解释
- 虚心接受建议
维护管理
定期清理
- 删除垃圾评论
- 清理重复评论
- 更新黑名单
- 审查举报评论
数据备份
- 定期备份评论数据
- 导出重要评论
- 保存用户反馈
常见问题
如何批量删除垃圾评论?
- 评论管理 → 筛选垃圾评论
- 勾选要删除的评论
- 批量操作 → 删除
- 确认
如何关闭某篇文章的评论?
- 编辑文章
- 取消勾选"允许评论"
- 保存
或
- 文章列表勾选文章
- 批量操作 → 关闭评论
评论如何防止灌水?
防护措施:
- 开启验证码
- 设置评论间隔
- 限制每日评论数
- IP 频率限制
- 敏感词过滤
- 黑名单机制
如何导出评论数据?
评论管理 → 导出
选择导出格式:Excel / CSV / JSON
选择导出范围
开始导出
第三方评论系统
如果需要更强大的评论功能,可以集成第三方评论系统:
Disqus
<div id="disqus_thread"></div>
<script>
var disqus_config = function () {
this.page.url = '{{ article.url }}';
this.page.identifier = '{{ article.id }}';
};
(function() {
var d = document, s = d.createElement('script');
s.src = 'https://your-site.disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>
畅言
<div id="SOHUCS"></div>
<script>
(function(){
var appid = 'your-app-id';
var conf = 'your-conf';
var width = window.innerWidth || document.documentElement.clientWidth;
if (width < 960) {
window.document.write('<script id="changyan_mobile_js" charset="utf-8" type="text/javascript" src="https://cy-cdn.kuaizhan.com/upload/mobile/wap-js/changyan_mobile.js?client_id=' + appid + '&conf=' + conf + '"><\/script>');
} else {
var loadJs=function(d,a){var c=document.getElementsByTagName("head")[0]||document.head||document.documentElement;var b=document.createElement("script");b.setAttribute("type","text/javascript");b.setAttribute("charset","UTF-8");b.setAttribute("src",d);if(typeof a==="function"){if(window.attachEvent){b.onreadystatechange=function(){var e=b.readyState;if(e==="loaded"||e==="complete"){b.onreadystatechange=null;a()}}}else{b.onload=a}}c.appendChild(b)};loadJs("https://cy-cdn.kuaizhan.com/upload/changyan.js",function(){window.changyan.api.config({appid:appid,conf:conf})});
}
})();
</script>
