在网站运营中,收集用户反馈和咨询是提升服务质量、了解用户需求的重要环节。安企CMS(AnQiCMS)提供了一套灵活且强大的留言管理功能,让您能够轻松地在前端模板中展示留言表单,并支持自定义字段,以满足不同业务场景下的信息收集需求。

要实现在AnQiCMS模板中动态显示用户提交的留言表单及其自定义字段,我们主要会用到一个核心标签:guestbook。这个标签能够获取您在后台配置的所有留言字段信息,并通过循环将其渲染到前端页面上,从而构建出一个完全动态化的留言表单。

了解 guestbook 标签

guestbook 标签是安企CMS专为留言表单设计,它的基本用法非常直观:

{% guestbook fields %}
    {# 在这里循环渲染表单字段 #}
{% endguestbook %}

当您使用 {% guestbook fields %} 时,它会返回一个名为 fields 的变量。这个 fields 变量是一个数组,其中包含了您在安企CMS后台“功能管理”下的“网站留言”中所有配置的表单字段信息,包括系统默认字段和您创建的自定义字段。

此外,如果您正在管理多个站点,并且希望在当前站点的模板中调用其他站点的留言表单字段,可以通过 siteId 参数来指定站点ID,例如 {% guestbook fields with siteId="2" %}

动态渲染留言表单字段

fields 变量中的每一个元素都代表一个留言表单字段。在循环遍历 fields 数组时,我们可以获取到每个字段的详细属性,并根据这些属性来动态生成相应的HTML表单元素。

每个字段对象(通常在循环中被命名为 item)会包含以下几个关键属性:

  • item.Name: 字段的显示名称,例如“您的姓名”、“联系电话”等。
  • item.FieldName: 字段的内部标识符,用于作为HTML表单元素的 name 属性,例如 user_namecontact 或您自定义字段的驼峰命名形式。
  • item.Type: 字段的类型,决定了应该渲染哪种HTML表单元素。常见的类型包括:
    • text:单行文本输入框 (<input type="text">)
    • number:数字输入框 (<input type="number">)
    • textarea:多行文本输入框 (<textarea>)
    • radio:单选按钮组 (<input type="radio">)
    • checkbox:多选按钮组 (<input type="checkbox">)
    • select:下拉选择框 (<select>)
  • item.Required: 布尔值,表示该字段是否为必填项。如果为 true,我们可以在HTML元素中添加 required 属性。
  • item.Content: 字段的默认值或占位符文本。
  • item.Items: 当字段类型为 radiocheckboxselect 时,这个属性会是一个数组,包含了所有可供选择的选项值。我们需要再次循环这个 item.Items 数组来生成选项。

构建留言表单的通用模板代码

有了这些字段信息,我们就可以构建一个通用的模板代码,它能够自动适应后台配置的变化,无需手动修改前端HTML。

以下是一个详尽的示例,展示了如何在模板中动态渲染留言表单,并包含了常用的文本、数字、多行文本、单选、多选、下拉选择以及验证码功能:

”`twig

{# 隐藏字段,用于指定后端返回格式,例如设置为'html'会返回HTML页面,'json'则返回JSON数据 #}
<input type="hidden" name="return" value="html">

{% guestbook fields %}
    {% for item in fields %}
        <div class="form-group">
            <label for="{{ item.FieldName }}">{{ item.Name }}{% if item.Required %}<span class="required-star">*</span>{% endif %}</label>
            <div>
                {% if item.Type == "text" or item.Type == "number" %}
                    <input type="{{ item.Type }}"
                           id="{{ item.FieldName }}"
                           name="{{ item.FieldName }}"
                           {% if item.Required %}required{% endif %}
                           placeholder="{{ item.Content }}"
                           class="form-control"
                           autocomplete="off">
                {% elif item.Type == "textarea" %}
                    <textarea id="{{ item.FieldName }}"
                              name="{{ item.FieldName }}"
                              {% if item.Required %}required{% endif %}
                              placeholder="{{ item.Content }}"
                              rows="5"
                              class="form-control"></textarea>
                {% elif item.Type == "radio" %}
                    <div class="form-check-group">
                        {% for val in item.Items %}
                            <input type="radio"
                                   id="{{ item.FieldName }}_{{ loop.index }}"
                                   name="{{ item.FieldName }}"
                                   value="{{ val }}"
                                   {% if item.Required %}required{% endif %}
                                   class="form-check-input">
                            <label for="{{ item.FieldName }}_{{ loop.index }}" class="form-check-label">{{ val }}</label>
                        {% endfor %}
                    </div>
                {% elif item.Type == "checkbox" %}
                    <div class="form-check-group">
                        {% for val in item.Items %}
                            <input type="checkbox"
                                   id="{{ item.FieldName }}_{{ loop.index }}"
                                   name="{{ item.FieldName }}[]" {# 多选时name属性需要加[] #}
                                   value="{{ val }}"
                                   class="form-check-input">
                            <label for="{{ item.FieldName }}_{{ loop.index }}" class="form-check-label">{{ val }}</label>
                        {% endfor %}
                        {# 如果需要必填,可以考虑通过JS进行校验,或将Required放在一个隐藏字段中辅助判断 #}
                    </div>
                {% elif item.Type == "select" %}
                    <select id="{{ item.FieldName }}"
                            name="{{ item.FieldName }}"
                            {% if item.Required %}required{% endif %}
                            class="form-control">
                        {% if not item.Required %}<option value="">请选择</option>{% endif %} {# 非必填时提供空选项 #}
                        {% for val in item.Items %}
                            <option value="{{ val }}">{{ val }}</option>
                        {% endfor %}
                    </select>
                {% endif %}
            </div>
        </div>
    {% endfor %}
{% endguestbook %}

{# 验证码部分:如果后台开启了留言验证码功能,这部分代码是必需的 #}
<div class="form-group captcha-group">
    <label for="captcha">验证码<span class="required-star">*</span></label>
    <div class="captcha-input-wrapper">
        <input type="hidden" name="captcha_id" id="captcha_id">
        <input type="text" name="captcha" id="captcha" required placeholder="请填写验证码" class="form-control captcha-input" autocomplete="off">
        <img src="" id="get-captcha" class="captcha-image" alt="验证码" title="点击刷新验证码" style="cursor: pointer;">
    </div>
</div>
<script>
    // JavaScript 用于刷新验证码
    document.getElementById('get-captcha').addEventListener("click", function (e) {
        fetch('/api/captcha')
            .then(response => response.json())
            .then(res => {
                document.getElementById('captcha_id').setAttribute("value", res.data.captcha_id);
                document.getElementById('get-captcha').setAttribute("src", res.data.captcha);
            }).catch(err => console.error("获取验证码失败:", err));
    });
    document.getElementById('get-captcha').click(); // 页面加载时自动获取一次验证码
</script>

<div class="form-group form-actions">
    <button type="submit" class="btn btn-primary">提交留言</button>
    <button type="reset" class="btn btn-secondary">重置</button>
</div>

</