1. 设置项目结构
questionnaire-system/
  client/             // 前端应用
    src/
      components/     // React组件
      pages/          // 页面
      App.js
      index.js
  server/             // 后端服务
    routes/           // 路由
    models/           // 数据模型
    app.js
  package.json
 
2. 启动前端应用
在client目录下,创建React应用并启动它:
npx create-react-app .
npm start
 
3. 设置Express后端
在server目录下,设置Express后端:
npm init -y
npm install express mongoose body-parser cors
 
在server/app.js中设置Express应用:
const express = require("express");
const cors = require("cors");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const app = express();
app.use(cors());
app.use(bodyParser.json());
// 设置数据库连接
mongoose.connect("mongodb://localhost/questionnaire", {
  useNewUrlParser: true,
  useUnifiedTopology: true,
});
const db = mongoose.connection;
db.on("error", console.error.bind(console, "数据库连接错误"));
db.once("open", function () {
  console.log("数据库连接成功");
});
// 设置路由
const authRoutes = require("./routes/auth");
const questionnaireRoutes = require("./routes/questionnaire");
app.use("/auth", authRoutes);
app.use("/questionnaire", questionnaireRoutes);
app.listen(5000, () => {
  console.log("后端服务已启动,端口5000");
});
 
4. 创建Express路由
在server/routes目录下,创建路由文件,例如auth.js和questionnaire.js,以处理用户身份验证和问卷操作。
创建auth.js用于用户身份验证:
const express = require("express");
const router = express.Router();
// 处理用户注册
router.post("/register", (req, res) => {
  // 实现用户注册逻辑
});
// 处理用户登录
router.post("/login", (req, res) => {
  // 实现用户登录逻辑
});
// 处理用户注销
router.post("/logout", (req, res) => {
  // 实现用户注销逻辑
});
module.exports = router;
 
创建questionnaire.js用于问卷操作:
const express = require("express");
const router = express.Router();
// 处理创建问卷
router.post("/create", (req, res) => {
  // 实现创建问卷逻辑
});
// 处理发布问卷
router.post("/publish", (req, res) => {
  // 实现发布问卷逻辑
});
// 处理填写问卷
router.post("/submit", (req, res) => {
  // 实现填写问卷逻辑
});
// 处理查看问卷结果
router.get("/results/:id", (req, res) => {
  const questionnaireId = req.params.id;
  // 实现查看问卷结果逻辑
});
module.exports = router;
 
5. 创建数据模型
在server/models目录下,创建Mongoose模型来定义用户、问卷等数据结构。
在server/models目录下,创建一个名为User.js的文件来定义用户数据模型:
const mongoose = require("mongoose");
const userSchema = new mongoose.Schema({
  username: {
    type: String,
    required: true,
    unique: true,
  },
  password: {
    type: String,
    required: true,
  },
  email: {
    type: String,
    required: true,
    unique: true,
  },
  // 其他用户相关字段
});
const User = mongoose.model("User", userSchema);
module.exports = User;
 
然后,创建一个名为Questionnaire.js的文件来定义问卷数据模型:
const mongoose = require("mongoose");
const questionnaireSchema = new mongoose.Schema({
  title: {
    type: String,
    required: true,
  },
  description: String,
  questions: [
    {
      type: mongoose.Schema.Types.ObjectId,
      ref: "Question",
    },
  ],
  // 其他问卷相关字段
});
const Questionnaire = mongoose.model("Questionnaire", questionnaireSchema);
module.exports = Questionnaire;
 
在Express应用的server/app.js文件中,确保您已经连接了MongoDB数据库
mongoose.connect("mongodb://localhost/questionnaire", {
  useNewUrlParser: true,
  useUnifiedTopology: true,
});
 
6. 设置React组件和页面
在前端应用中,创建React组件和页面来实现问卷设计、问卷发布、问卷填写、账户管理等功能。
在前端应用中,您需要创建React组件和页面来实现不同的功能,包括问卷设计、问卷发布、问卷填写和账户管理。以下是一个项目结构:
client/
  src/
    components/
      Auth/           // 用户身份验证相关组件
      Questionnaire/  // 问卷相关组件
      Account/        // 账户管理相关组件
    pages/
      Home.js         // 主页
      Login.js        // 登录页
      Register.js     // 注册页
      CreateQuestionnaire.js  // 创建问卷页
      FillQuestionnaire.js    // 填写问卷页
      AccountSettings.js      // 账户设置页
    App.js             // 主应用组件
    index.js           // 渲染应用
 
CreateQuestionnaire.js 代码
import React, { useState } from "react";
function CreateQuestionnaire() {
  const [questionnaire, setQuestionnaire] = useState({
    title: "",
    description: "",
    questions: [],
  });
  const addQuestion = () => {
    // 在状态中添加新问题
    const newQuestion = {
      text: "",
      options: [],
    };
    setQuestionnaire((prev) => ({
      ...prev,
      questions: [...prev.questions, newQuestion],
    }));
  };
  const handleQuestionChange = (index, field, value) => {
    // 更新特定问题的字段
    setQuestionnaire((prev) => {
      const updatedQuestions = [...prev.questions];
      updatedQuestions[index][field] = value;
      return { ...prev, questions: updatedQuestions };
    });
  };
  const saveQuestionnaire = () => {
    // 将问卷数据发送到后端保存
    // 可以使用Fetch或Axios发送POST请求
    console.log("保存问卷数据:", questionnaire);
  };
  return (
    <div>
      <h2>Create Questionnaire</h2>
      <div>
        <label>Title:</label>
        <input
          type="text"
          value={questionnaire.title}
          onChange={(e) => setQuestionnaire({ ...questionnaire, title: e.target.value })}
        />
      </div>
      <div>
        <label>Description:</label>
        <textarea
          value={questionnaire.description}
          onChange={(e) => setQuestionnaire({ ...questionnaire, description: e.target.value })}
        />
      </div>
      <h3>Questions</h3>
      {questionnaire.questions.map((question, index) => (
        <div key={index}>
          <input
            type="text"
            placeholder="Enter your question"
            value={question.text}
            onChange={(e) => handleQuestionChange(index, "text", e.target.value)}
          />
          <button onClick={addQuestion}>Add Question</button>
        </div>
      ))}
      <button onClick={addQuestion}>Add Question</button>
      <button onClick={saveQuestionnaire}>Save Questionnaire</button>
    </div>
  );
}
export default CreateQuestionnaire;
 
7. 实现问卷设计和发布
允许用户创建问卷,并将问卷保存到数据库。允许用户发布问卷链接。
- 在后端设置一个路由来接收前端发送的问卷数据并将其保存到数据库。
 - 生成一个唯一的问卷标识符,以便后续用户填写问卷时使用。
 - 返回问卷的标识符作为发布链接
 
const express = require("express");
const router = express.Router();
const Questionnaire = require("../models/Questionnaire");
// 创建问卷
router.post("/create", async (req, res) => {
  const { title, description, questions } = req.body;
  try {
    const newQuestionnaire = new Questionnaire({
      title,
      description,
      questions,
    });
    const savedQuestionnaire = await newQuestionnaire.save();
    res.json({ questionnaireId: savedQuestionnaire._id });
  } catch (error) {
    res.status(500).json({ error: "问卷保存失败" });
  }
});
// ...其他问卷相关路由
module.exports = router;
 
8. 实现问卷填写和收集
用户可以填写问卷,并将答案保存到数据库。
前端实现:
- 创建一个页面,显示问卷的问题,并允许用户填写答案。
 - 用户填写完问卷后,将答案数据发送到后端以进行保存。
 
下面是FillQuestionnaire.js 组件的更新,以包括保存答案到后端的功能。
import React, { useState } from "react";
import axios from "axios";
function FillQuestionnaire({ questionnaireId }) {
  const [answers, setAnswers] = useState([]);
  const [questionnaire, setQuestionnaire] = useState(null);
  // 从后端获取问卷数据
  useEffect(() => {
    axios.get(`/api/questionnaire/${questionnaireId}`).then((response) => {
      setQuestionnaire(response.data);
    });
  }, [questionnaireId]);
  const handleAnswerChange = (questionIndex, answer) => {
    // 更新答案
    const updatedAnswers = [...answers];
    updatedAnswers[questionIndex] = answer;
    setAnswers(updatedAnswers);
  };
  const submitAnswers = () => {
    // 将答案数据发送到后端保存
    axios
      .post(`/api/questionnaire/submit/${questionnaireId}`, { answers })
      .then((response) => {
        console.log("答案提交成功", response.data);
        // 可以进行其他操作,如重定向到感谢页面
      })
      .catch((error) => {
        console.error("答案提交失败", error);
      });
  };
  return (
    <div>
      {questionnaire && (
        <div>
          <h2>{questionnaire.title}</h2>
          <p>{questionnaire.description}</p>
          <form>
            {questionnaire.questions.map((question, index) => (
              <div key={index}>
                <p>{question.text}</p>
                {/* 根据问题类型渲染相应的答案输入框 */}
                {question.type === "text" ? (
                  <input
                    type="text"
                    value={answers[index] || ""}
                    onChange={(e) => handleAnswerChange(index, e.target.value)}
                  />
                ) : (
                  // 渲染其他类型的答案输入框
                )}
              </div>
            ))}
          </form>
          <button onClick={submitAnswers}>Submit Answers</button>
        </div>
      )}
    </div>
  );
}
export default FillQuestionnaire;
 
后端实现:
- 在后端设置一个路由来接收前端发送的答案数据并将其保存到数据库。
 - 根据问卷标识符,将答案与问卷关联。
 
以下是一个简化的后端路由 server/routes/questionnaire.js:
const express = require("express");
const router = express.Router();
const Questionnaire = require("../models/Questionnaire");
// 提交问卷答案
router.post("/submit/:questionnaireId", async (req, res) => {
  const questionnaireId = req.params.questionnaireId;
  const answers = req.body.answers;
  try {
    const questionnaire = await Questionnaire.findById(questionnaireId);
    if (!questionnaire) {
      return res.status(404).json({ error: "问卷不存在" });
    }
    // 将答案与问卷关联,保存到数据库
    // 您可以根据实际需求设计数据库结构来存储答案数据
    res.json({ message: "答案保存成功" });
  } catch (error) {
    res.status(500).json({ error: "答案保存失败" });
  }
});
// ...其他问卷相关路由
module.exports = router;










