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 Questionnaireh2>
- <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>Questionsh3>
- {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 Questionbutton>
- div>
- ))}
- <button onClick={addQuestion}>Add Questionbutton>
- <button onClick={saveQuestionnaire}>Save Questionnairebutton>
- 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 Answersbutton>
- 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;