作为一名深谙安企CMS运营之道的网站内容专家,我深知读者对互动性和信息透明度的需求。评论功能是用户参与网站内容建设、表达观点的重要途径,而多级回复则能有效促进用户之间的深度交流。安企CMS为我们提供了强大且灵活的评论管理机制,使得获取和展示评论列表,包括多级回复,变得高效便捷。

在安企CMS中,获取和显示网站的评论列表主要依赖于其强大的模板标签体系,特别是 commentList 标签。这个标签允许我们根据不同的需求筛选、排序和展示评论数据,并天然支持多级回复的结构,极大地简化了开发工作。

获取评论数据

要显示评论列表,我们首先需要使用 commentList 标签来获取评论数据。这个标签通常在文档详情页使用,因为它需要关联到具体的文章或产品。它接受多个参数来精确控制所获取的评论范围和显示方式。

首先,archiveId 参数是必不可少的,它指定了我们要获取哪篇文档(文章或产品)的评论。例如,如果当前页面是一篇文档详情页,我们可以通过 {% archiveDetail with name="Id" %} 来动态获取当前文档的ID,并将其作为 archiveId 的值。

其次,type 参数决定了评论列表的展示类型。当我们希望一次性显示所有评论,或者需要自定义分页逻辑时,可以使用 type="list"。而如果我们需要安企CMS内置的分页功能来管理大量评论,则应将 type 设置为 "page"

limit 参数则用于控制每次获取评论的数量。这在显示“最新评论”或限制每页显示评论数量时非常有用。例如,limit="10" 将显示10条评论。如果我们需要从某个偏移量开始获取,也可以使用逗号分隔的格式,如 limit="2,10" 表示从第3条评论开始获取10条。

此外,order 参数允许我们定义评论的排序方式,例如 order="id desc" 可以按评论ID倒序排列(通常意味着最新评论在前),order="id asc" 则按ID正序排列。对于拥有多站点的运营者,siteId 参数可以用来指定获取特定站点的评论数据,但如果不需要跨站调用,一般无需填写。

所有通过 commentList 标签获取到的评论数据会以一个数组对象的形式赋值给我们指定的变量名。例如,如果我们使用 {% commentList comments with archiveId=archive.Id type="list" limit="6" %},那么 comments 变量将包含一个评论对象的数组,我们可以通过 for 循环来遍历并显示这些评论。

展示评论列表与多级回复

获取到评论数据后,我们就可以在模板中使用 for 循环来遍历 comments 变量并展示每一条评论。每个评论对象都包含了一系列字段,如 Id (评论ID), UserName (评论者用户名), Content (评论内容), CreatedTime (评论时间) 等。

在展示评论内容时,一个重要的考虑是评论的审核状态。Status 字段用于指示评论是否通过审核。通常,我们只显示 Status 为 1(审核通过)的评论。对于正在审核中的评论,我们可以选择显示一个提示信息或进行截断处理,以保护用户隐私并避免显示不当内容。

实现多级回复是评论功能的核心亮点。在安企CMS的评论数据结构中,每个评论对象都包含一个 Parent 字段。如果当前评论是对另一条评论的回复,那么 Parent 字段将包含被回复评论的完整数据(包括其 UserNameContent 等)。我们可以通过判断 item.Parent 是否存在来确定当前评论是否为回复。

item.Parent 存在时,我们可以在模板中嵌套显示被回复评论的内容,通常以引用块(<blockquote>)的形式展示,以清晰地区分回复关系。同时,我们也需要对 Parent 评论的 Status 进行检查,以确保只显示已审核通过的父级评论内容。这样的设计使得评论层级清晰可见,用户能够轻松追踪对话上下文。

以下是一个展示常规评论和多级回复的模板代码示例:

{# 假设我们已经在文档详情页获取了当前文档的ID,并赋值给 archive.Id #}
<div class="comment-section">
    <h3>用户评论</h3>
    {% commentList comments with archiveId=archive.Id type="list" limit="6" %}
        {% for item in comments %}
            <div class="comment-item">
                <div class="comment-header">
                    <span class="comment-user">
                        {% if item.Status != 1 %}
                            审核中:{{item.UserName|truncatechars:6}}
                        {% else %}
                            {{item.UserName}}
                        {% endif %}
                    </span>
                    {% if item.Parent %}
                        <span class="comment-reply-indicator">回复</span>
                        <span class="comment-parent-user">
                            {% if item.Parent.Status != 1 %}
                                审核中:{{item.Parent.UserName|truncatechars:6}}
                            {% else %}
                                {{item.Parent.UserName}}
                            {% endif %}
                        </span>
                    {% endif %}
                    <span class="comment-time">{{stampToDate(item.CreatedTime, "2006-01-02 15:04")}}</span>
                </div>
                <div class="comment-content">
                    {% if item.Parent %}
                        <blockquote class="comment-quote">
                            {% if item.Parent.Status != 1 %}
                                该父评论正在审核中:{{item.Parent.Content|truncatechars:9}}
                            {% else %}
                                {{item.Parent.Content|truncatechars:100}}
                            {% endif %}
                        </blockquote>
                    {% endif %}
                    {% if item.Status != 1 %}
                        该评论正在审核中:{{item.Content|truncatechars:9}}
                    {% else %}
                        {{item.Content}}
                    {% endif %}
                </div>
                <div class="comment-actions" data-id="{{item.Id}}" data-user="{{item.UserName}}">
                    <a class="action-item comment-praise" data-id="praise">赞(<span class="vote-count">{{item.VoteCount}}</span>)</a>
                    <a class="action-item comment-reply" data-id="reply">回复</a>
                </div>
            </div>
        {% empty %}
            <p>暂无评论,快来发表您的看法吧!</p>
        {% endfor %}
    {% endcommentList %}
</div>

评论列表分页显示

当评论数量较多时,分页显示可以提升页面加载速度和用户体验。通过将 commentListtype 参数设置为 "page",我们可以利用安企CMS内置的分页功能。随后,结合 pagination 标签,即可生成完整的评论分页导航。pagination 标签提供了总条数、总页数、当前页、首页、末页、上一页、下一页以及中间页码等丰富的数据,我们可以灵活构建分页链接。

{# 假设 comments 变量已通过 type="page" 获取评论数据 #}
<div class="comment-pagination">
    {% pagination pages with show="5" %}
        <ul>
            <li class="page-info">总计:{{pages.TotalItems}}条评论,共{{pages.TotalPages}}页,当前第{{pages.CurrentPage}}页</li>
            <li class="page-item {% if pages.FirstPage.IsCurrent %}active{% endif %}"><a href="{{pages.FirstPage.Link}}">首页</a></li>
            {% if pages.PrevPage %}
                <li class="page-item"><a href="{{pages.PrevPage.Link}}">上一页</a></li>
            {% endif %}
            {% for item in pages.Pages %}
                <li class="page-item {% if item.IsCurrent %}active{% endif %}"><a href="{{item.Link}}">{{item.Name}}</a></li>
            {% endfor %}
            {% if pages.NextPage %}
                <li class="page-item"><a href="{{pages.NextPage.Link}}">下一页</a></li>
            {% endif %}
            <li class="page-item {% if pages.LastPage.IsCurrent %}active{% endif %}"><a href="{{pages.LastPage.Link}}">末页</a></li>
        </ul>
    {% endpagination %}
</div>

提交评论与回复表单

用户通过HTML表单提交评论和回复。提交的目标地址是 /comment/publish。为了实现回复功能,除了常规的 archive_id (文档ID), user_name (评论者名称), content (评论内容) 外,我们还需要一个 parent_id 字段。当用户回复某条评论时,前端JavaScript会将该评论的 Id 填充到 parent_id 字段中。

此外,为了确保评论系统的安全性,集成验证码功能是必不可少的。安企CMS支持通过 tag-captcha.md 文档中描述的方法在后台启用验证码,并在前端表单中添加验证码字段和图片。这能有效防止垃圾评论和恶意刷屏。

<form method="post" action="/comment/publish" class="comment-submit-form">
    <input type="hidden" name="return" value="html"> {# 可选值:html 或 json,决定后端返回格式 #}
    <input type="hidden" name="archive_id" value="{% archiveDetail with name="Id" %}">
    <input type="hidden" name="parent_id" id="parent_comment_id" value=""> {# 用于存储回复的父评论ID #}

    <div class="form-group">
        <label for="user_name">您的昵称:</label>
        <input type="text" name="user_name" id="user_name" required placeholder="请填写您的昵称">
    </div>

    <div class="form-group" id="reply-to-info" style="display: none;">
        回复 <span id="reply-to-user"></span>:<a href="javascript:void(0);" id="cancel-reply">取消回复</a>
    </div>

    <div class="form-group">
        <label for="content">评论内容:</label>
        <textarea name="content" id="content" required placeholder="请输入您的评论内容" rows="5"></textarea>
    </div>

    <div class="form-group captcha-group">
        <input type="hidden" name="captcha_id" id="captcha_id">
        <input type="text" name="captcha" required placeholder="请填写验证码">
        <img src="" id="get-captcha" alt="验证码">
    </div>

    <div class="form-actions">
        <button type="submit">提交评论</button>
        <button type="reset">重置</button>
    </div>
</form>

<script>
    // 验证码加载逻辑 (根据 tag-captcha.md 调整)
    document.getElementById('get-captcha').addEventListener("click", function () {
        fetch('/api/captcha')
            .then(response => response.json())
            .then(res => {
                document.getElementById('captcha_id').value = res.data.captcha_id;
                document.getElementById('get-captcha').src = res.data.captcha;
            }).catch(err => console.error('Error loading captcha:', err));
    });
    document.getElementById('get-captcha').click(); // 首次加载验证码

    // 回复功能逻辑
    document.querySelectorAll('.comment-reply').forEach(button => {
        button.addEventListener('click', function() {
            const commentId = this.closest('.comment-actions').dataset.id;
            const userName = this.closest('.comment-actions').dataset.user;
            document.getElementById('parent_comment_id').value = commentId;
            document.getElementById('reply-to-user').textContent = userName;
            document.getElementById('reply-to-info').style.display = 'block';
            document.getElementById('content').focus();
        });
    });

    document.getElementById('cancel-reply').addEventListener('click', function() {
        document.getElementById('parent_comment_id').value = '';
        document.getElementById('reply-to-user').textContent = '';
        document.getElementById('reply-to-info').style.display = 'none';
    });

    // 评论点赞功能 (AJAX 示例)
    document.querySelectorAll('.comment-praise').forEach(button => {
        button.addEventListener('click', function() {
            const commentId = this.closest('.comment-actions').dataset.id;
            const voteCountSpan = this.querySelector('.vote-count');
            fetch('/comment/praise', {
                method: 'POST',
                headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                body: `id=${commentId}`
            })
            .then(response => response.json())
            .then(res => {
                if (res.code === 0) {
                    alert(res.msg);
                    voteCountSpan.textContent = res.data.vote_count;
                } else {
                    alert(res.msg);
                }
            })
            .catch(err => console.error('Error praising comment:', err));
        });
    });
</script>

在模板设计方面,评论列表页的模板文件通常会命名为 comment/list.html,以符合安企CMS的模板约定。这样,系统就能自动识别并应用该模板。通过以上步骤,我们不仅能获取和展示结构清晰的评论列表,包括其多级回复关系,还能提供完整的评论提交和互动功能,为网站带来更丰富的用户参与体验。

常见问题解答

  1. 如何开启评论功能并进行管理? 安企CMS内置了内容评论管理功能。您可以在后台的“功能管理”菜单下找到“内容评论”选项,在这里您可以开启或关闭评论功能,设置评论是否需要审核,以及管理已发布的评论,包括删除、修改或回复等操作。

  2. 我的评论列表为什么没有显示多级回复? 请检查您的模板代码,确保在遍历评论列表时,