使用React、Express实现一个问卷发布/收集系统

news/2024/7/15 17:29:19 标签: react.js, express, 前端

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.jsquestionnaire.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. 实现问卷设计和发布

允许用户创建问卷,并将问卷保存到数据库。允许用户发布问卷链接。

  1. 在后端设置一个路由来接收前端发送的问卷数据并将其保存到数据库。
  2. 生成一个唯一的问卷标识符,以便后续用户填写问卷时使用。
  3. 返回问卷的标识符作为发布链接
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. 实现问卷填写和收集

用户可以填写问卷,并将答案保存到数据库。

前端实现:

  1. 创建一个页面,显示问卷的问题,并允许用户填写答案。
  2. 用户填写完问卷后,将答案数据发送到后端以进行保存。

下面是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;

后端实现:

  1. 在后端设置一个路由来接收前端发送的答案数据并将其保存到数据库。
  2. 根据问卷标识符,将答案与问卷关联。

以下是一个简化的后端路由 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;


http://www.niftyadmin.cn/n/5089786.html

相关文章

【更新】囚生CYの备忘录(202331014~)

文章目录 20221014 20221014 本以为下午怡宝的比赛至少是能跑到前三&#xff0c;结果连前五都没混到&#xff0c;赛前都知道路线不可能有5km&#xff0c;因为即便是绕着主校区最外沿跑一圈也才4km出头&#xff0c;我估摸着大概是2500米&#xff0c;结果实际上只有1700米&#x…

系统架构师备考倒计时22天(每日知识点)

测试阶段划分 单元测试&#xff1a;依据详细设计&#xff0c;模块测试&#xff0c;模块功能、性能、接口等集成测试&#xff1a;依据概要设计&#xff0c;模块间的接口系统测试&#xff1a;依据需求文档&#xff0c;在真实环境下&#xff0c;验证完整的软件配置项能否和系统正…

【Java学习之道】JavaFx 框架与组件介绍

引言 如果你曾经尝试过使用Java编写一个漂亮的窗口应用程序&#xff0c;那么你一定知道JavaFX这个强大的工具。JavaFX是Java 8中引入的一个GUI开发框架&#xff0c;它提供了丰富的组件和功能&#xff0c;使得我们可以轻松地创建出功能强大、界面美观的桌面应用程序。无论你是想…

利用Python提取将Excel/PDF文件数据

使用Python来创建一个接口&#xff0c;用于接收Excel文件资源链接&#xff0c;下载文件并执行指定的操作&#xff0c;然后返回处理后的数据。以下是一个基本的示例&#xff0c;展示如何使用Flask来创建这样的接口。请注意&#xff0c;这是一个简化的示例&#xff0c;您可能需要…

建立一个新的高阶数学教授模式,知其然,知其用,知其之所以然,知其所以然

1. 传统常用的模式 概念&#xff0c;性质&#xff0c;定理&#xff0c;定理证明&#xff0c;定理应用&#xff1b; 这个学习模式挺好的&#xff0c;但是定理证明过程往往很冗长&#xff0c;而且不易记忆&#xff0c;也就是说&#xff0c;即使推导了定理&#xff0c;初学者也记…

写一个chrome插件,一键下载amazon商品评论

写一个chrome插件&#xff0c;一键下载amazon商品评论 功能列表&#xff1a; 1&#xff0c;popup页&#xff1a;设置需要导出评论数&#xff0c;评论关键词&#xff0c;排序&#xff0c;是否包含图片和视频&#xff0c;好评度&#xff0c;是否购买后评论 2&#xff0c;popup…

【Java 进阶篇】JavaScript 中的全局对象和变量

JavaScript 是一门非常强大的编程语言&#xff0c;它提供了许多全局对象和变量&#xff0c;以便于在整个应用程序中共享数据和功能。本文将详细介绍 JavaScript 中的全局对象和变量&#xff0c;包括全局对象、全局变量、全局函数以及它们的用途和示例。 全局对象 JavaScript …

好的摄影师都会iPhone 8和iOS 11的这三项功能

众所周知&#xff0c;苹果的手机像素一直处于智能手机摄影的前沿&#xff0c;在即将到来的九月&#xff0c;苹果公司准备证明他拥有最好的相机技术。 虽然我们还不知道iPhone 8摄像头的具体细节&#xff0c;如几百万像素、光学变焦是多少&#xff0c;但我们确实知道苹果正在给i…