You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为调查问卷的每个问题添加评论功能与多文件上传功能?

实现调查问卷的单问题评论与多文件上传功能

前端实现思路

每个问卷问题模块需要单独挂载评论输入和文件上传组件,核心是把评论内容、文件列表与对应问题的ID绑定,通过FormData实现多类型数据的提交。

基础HTML结构

给每个问题包裹独立容器,包含评论输入框、多文件上传控件和提交按钮:

<!-- 单个问题模块 -->
<div class="question-block" data-question-id="q1">
  <h3>问题1:请描述您使用产品的场景</h3>
  <textarea class="question-comment" placeholder="写下您的补充评论..."></textarea>
  <input type="file" class="question-files" multiple accept=".pdf,.doc,.docx,.jpg,.png">
  <button class="submit-comment-btn">提交评论与文件</button>
</div>

JavaScript处理提交逻辑

监听按钮点击,收集当前问题的ID、评论内容和选中的文件,用FormData封装后发送请求:

document.querySelectorAll('.submit-comment-btn').forEach(btn => {
  btn.addEventListener('click', function() {
    const questionBlock = this.closest('.question-block');
    const questionId = questionBlock.dataset.questionId;
    const commentContent = questionBlock.querySelector('.question-comment').value;
    const files = questionBlock.querySelector('.question-files').files;

    const formData = new FormData();
    formData.append('question_id', questionId);
    formData.append('comment', commentContent);
    // 批量添加文件
    for (let i = 0; i < files.length; i++) {
      formData.append('files[]', files[i]);
    }

    // 发送POST请求
    fetch('/submit-question-comment', {
      method: 'POST',
      body: formData
    })
    .then(res => res.json())
    .then(data => {
      if (data.success) {
        alert('提交成功');
        // 清空输入和文件选择
        questionBlock.querySelector('.question-comment').value = '';
        questionBlock.querySelector('.question-files').value = '';
      } else {
        alert(`提交失败:${data.message}`);
      }
    })
    .catch(err => console.error('提交出错:', err));
  });
});

后端处理方案

后端需要接收FormData,解析数据后完成评论存储、文件校验与上传,同时建立评论、文件与问题的关联。

Node.js + Express示例

使用multer中间件处理文件上传:

const express = require('express');
const multer = require('multer');
const path = require('path');
const app = express();

// 配置文件存储路径和文件名
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, './uploads/'); // 确保uploads目录存在
  },
  filename: function (req, file, cb) {
    // 生成唯一文件名,避免覆盖
    const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
    cb(null, file.fieldname + '-' + uniqueSuffix + path.extname(file.originalname));
  }
});

// 文件校验:限制类型和大小(5MB)
const fileFilter = (req, file, cb) => {
  const allowedTypes = ['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'image/jpeg', 'image/png'];
  if (allowedTypes.includes(file.mimetype) && file.size <= 5 * 1024 * 1024) {
    cb(null, true);
  } else {
    cb(new Error('仅支持PDF、Word、JPG/PNG格式,单文件不超过5MB'), false);
  }
};

const upload = multer({ storage: storage, fileFilter: fileFilter });

// 处理提交请求
app.post('/submit-question-comment', upload.array('files[]'), (req, res) => {
  try {
    const { question_id, comment } = req.body;
    const uploadedFiles = req.files.map(file => file.path); // 获取文件存储路径

    // 1. 将评论内容存入数据库(示例逻辑,需替换为实际DB操作)
    // db.query('INSERT INTO question_comments (question_id, content) VALUES (?, ?)', [question_id, comment]);
    // 2. 将文件路径与评论关联存入数据库
    // uploadedFiles.forEach(filePath => {
    //   db.query('INSERT INTO comment_files (comment_id, file_path) VALUES (?, ?)', [newCommentId, filePath]);
    // });

    res.json({ success: true, message: '评论与文件上传成功' });
  } catch (err) {
    res.status(400).json({ success: false, message: err.message });
  }
});

app.listen(3000, () => console.log('服务器运行在端口3000'));

Python + Flask示例

使用原生request.files处理:

from flask import Flask, request, jsonify
import os
from werkzeug.utils import secure_filename

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = './uploads/'
app.config['MAX_CONTENT_LENGTH'] = 5 * 1024 * 1024  # 5MB限制
ALLOWED_EXTENSIONS = {'pdf', 'doc', 'docx', 'jpg', 'jpeg', 'png'}

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

@app.route('/submit-question-comment', methods=['POST'])
def submit_comment():
    try:
        question_id = request.form.get('question_id')
        comment = request.form.get('comment')
        files = request.files.getlist('files[]')

        # 校验问题ID和评论(按需添加)
        if not question_id:
            return jsonify({'success': False, 'message': '缺少问题ID'}), 400

        uploaded_files = []
        for file in files:
            if file and allowed_file(file.filename):
                filename = secure_filename(file.filename)
                # 生成唯一文件名
                unique_filename = f"{os.path.splitext(filename)[0]}_{os.urandom(8).hex()}{os.path.splitext(filename)[1]}"
                file_path = os.path.join(app.config['UPLOAD_FOLDER'], unique_filename)
                file.save(file_path)
                uploaded_files.append(file_path)

        # 存入数据库逻辑(示例)
        # comment_id = db.execute('INSERT INTO question_comments (question_id, content) VALUES (?, ?)', (question_id, comment)).lastrowid
        # for fp in uploaded_files:
        #     db.execute('INSERT INTO comment_files (comment_id, file_path) VALUES (?, ?)', (comment_id, fp))
        # db.commit()

        return jsonify({'success': True, 'message': '提交成功'})
    except Exception as e:
        return jsonify({'success': False, 'message': str(e)}), 400

if __name__ == '__main__':
    os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
    app.run(debug=True)

关键注意事项

  • 数据关联:数据库需要设计三张核心表:question(问卷问题)、question_comment(评论,关联question_id)、comment_file(文件,关联comment_id),确保评论和文件能追溯到对应问题。
  • 前端体验优化:添加文件上传进度提示、已选文件预览、格式/大小校验提示,提升用户体验。
  • 安全防护:后端必须二次校验文件类型和大小,避免恶意文件上传;对文件名进行转义处理,防止路径遍历攻击;存储文件时使用随机文件名,避免冲突。
  • 存储方案:如果问卷流量大,建议将文件存储到云对象存储,而非本地服务器,减轻服务器压力并提升访问速度。

内容的提问来源于stack exchange,提问作者Mahdi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 00:52:26