vue开发测评系统思路及踩坑

news2025/6/29 22:28:37

最近公司做了一个测评系统,因为时间很短,本以为会很简单,没有想到踩了很多坑。

先看下部分效果图吧

 

 

 

 然后在说下需求 

1:所有的答案都是动态的(例如选择是出来的是第二题,选择否出来的是第五题)

2:没有答过的题不显示下一题按钮,答过的题显示上一题按钮

3:答过的题,返回上一题 显示上一题和下一题按钮(第一题和最后一题例外)

4:最后一题显示上一题和答案解析按钮

5:选择的时候 自动跳转到下一题

6:已经答过的题,更改后,从此题开始 后面答过的题清除(需求则是返回上一题,点击后不管有无更改 后面的题都清除,自己感觉不合理)

看似很简单,其实并不是很好处理 但是当思路捋清楚了 就很好做了 

先捋一捋思路 无非三种操作 上一题、下一题、和答题和三种按钮状态 上一题 下一题 查看答案

然后开始拆分功能

首先是答题

1.判断是不是最后一题

  1.1是:

        1.1.1 显示上一题按钮 

        1.1.2显示答案解析按钮

  1.2不是:

         1.2.1显示下一题按钮

         1.2.2 显示上一题按钮

          1.2.3对比和之前的变化 当前题是否有值

          1.2.3.1是  ==》哪一题开始清空

           1.2.3.2否  ===》清空

   2.选择赋值的时机

   3. 当前题点击的时候 判断是不是最后一题 (已经答过的题)

    3.1 当前题是第几题  =》从全部答案里面找 得到索引

    3.2 判断当前提是否答过

         答过:当前题的答案去匹配已经打过的题的当前题

         判断下一题是否有 

        有==》不处理

       五 ==》显示查看答案按钮

2.下一题

 2.1 显示上一题

2.2过滤已经答过的题目 =》找到当前题的索引

2.3判断当前题的下一题是否存在

    2.3.1不存在

     判断是否显示查看答案的按钮

    是  =》显示答案解析按钮

    否 =》 显示下一题

    2.3.2存在

    显示下一题

    判断是否最后一题 判断依据如下

    1从全部题里面找到当前题

    2从已经答过的题里面找到对应的索引‘

    3当前题的题目答案中匹配已答项的答案

    4判断当前题答案中是否有下一题

     有==》不处理

     无==》显示答案解析按钮 

 3 上一题

  3.1 显示下一题按钮 

  3.2 判断上一题按钮是否显示

  3.3 显示上一题

  3.4 记录答案

    看一下完整代码吧(vue3+vant)

<template>
  <div class="main">
    <template v-for="(item, i) in vDate.dataList" :key="i">
      <div class="item_list" v-show="item.questionId == vDate.questionId">
        <div class="item_title">
          {{ item.question }}
        </div>
        <van-radio-group
          v-model="vDate.answerList[i].questionOptionId"
        >
          <van-radio
            @click="radioClick(i,item,key)"
            v-for="(key, v) in item.optionList"
            :key="v"
            :name="key.questionOptionId"
            >{{ key.questionOption }}</van-radio
          >
        </van-radio-group>
      </div>
    </template>
		<div class="operate">
			<div>
        <van-button size="small" v-if="vDate.press>0" @click="press">上一题</van-button>
        <span v-else></span>
      </div>
			<div>
        <div v-if="vDate.next>0">
          <van-button type="primary" size="small" @click="lookAnswer" v-if="vDate.isAnswer">查看答案</van-button>
          <van-button type="primary" size="small" @click="next" v-else>下一题</van-button>
        </div>
			  <div v-else>
        </div>
      </div>
		</div>
  </div>
  <div>
    <van-overlay :show="vDate.show">
      <div class="wrapper" @click.stop>
        <van-cell-group inset>
         <div class="label">手机号</div>
          <van-field
            v-model="vDate.phone"
            center
            type="digit"
            :maxlength="11"
            placeholder="请输入手机号"
          >
            <template #button>
              <van-button type="primary" @click="vDate.flag && obtain()">{{vDate.content}}</van-button>
            </template>
          </van-field>
          <div class="input_control">
            <van-field v-model="vDate.pwdVal" :maxlength="4" type="digit" ref="verification" />
          </div>
          <div class="label">验证码</div>
          <div class='input_row' @click='getFocus'>
            <div class='pwd_item' v-for="(item,i) in 4" :key='i'>
                <span v-if="vDate.pwdVal.length>i">{{vDate.pwdVal[i]}}</span>
            </div>
          </div>
          <div class="operation">
            <van-button type="primary" block @click="toDetail">查看答案</van-button>
          </div>
        </van-cell-group>
      </div>
    </van-overlay>
  </div>
</template>
<script setup lang="ts">
import { nextTick, reactive, ref,onMounted } from "vue";
const verification = ref()
import {useRouter} from "vue-router"
import { Toast } from 'vant';
import {getQuestionList,submitQuestionList} from "@/api/index"
const router = useRouter()
const vDate:any = reactive({
	type:0,
  phone:'',
  show:false,
  flag:true,
  input:false,
  pwdVal:"",
  count:'',
  content:'获取验证码',
  countNumber:1,
  timer:null,
  dataList: [
  ],
  answerList:[
  ],
  questionId:'',
  isAnswer:false,
  idList:[],
  press:0,
  isNext:'',
  next:0,
  index:0,
  answerLists:[]
})
const phoneReg= /^1[3-9][0-9]{9}$/ 
// 上一题
function press(){
  vDate.next = 1
  vDate.isAnswer = false
  let answerList = vDate.answerList.filter((item:any)=>item.questionId)
  let length = answerList.length-1
  let index = answerList.findIndex((item:any)=>item.questionId==vDate.questionId)
  if(index==-1){
    vDate.press = answerList.length-1
    vDate.questionId = answerList[length].questionId
  }else{
    vDate.press = index-1
    vDate.questionId = answerList[index-1].questionId
  }
  vDate.answerLists = JSON.parse(JSON.stringify(vDate.answerList))
}
function next(){
  vDate.press = 1
	let answerList = vDate.answerList.filter((item:any)=>item.questionId)
  let index = answerList.findIndex((item:any)=>item.questionId == vDate.questionId )
  if(answerList[index+1]){
    vDate.questionId = answerList[index+1].questionId
      let nextArr = vDate.dataList.filter((item:any)=>item.questionId == vDate.questionId) //当前页项
      let indexs = vDate.answerList.findIndex((item:any)=>item.questionId == vDate.questionId)
      console.log(vDate.questionId,vDate.answerList[indexs],999,nextArr[0],"===========")

      let arr = nextArr[0].optionList.filter((item:any)=>item.questionOptionId == vDate.answerList[indexs].questionOptionId)
      if(!arr[0].relationQuestionId){
        vDate.isAnswer = true
        vDate.next = 1
      }
  }else{
    if(!vDate.isNext){
      vDate.isAnswer = true
    }else{
      vDate.next = -1
      vDate.questionId = vDate.isNext
      console.log(vDate.questionId,"22")
    }
  }
}
// 查看答案
const lookAnswer = ()=>{
  vDate.show = true
}
// 输入验证码
const getFocus = ()=>{
  nextTick(()=>{
    verification.value.focus()
  })
}
//答案
const toDetail = ()=>{
  if(!vDate.phone){
    return Toast('请输入手机号');
  }
  if(!phoneReg.test(vDate.phone)){
    return Toast('请输入正确手机号');
  }
  if(vDate.countNumber==1&&!vDate.pwdVal){
    return Toast('请获取验证码');
  }
  if(vDate.countNumber==2&&!vDate.pwdVal){
    return Toast('请输入验证码');
  }
  let userAnswerRequestList = vDate.answerList.filter((item:any)=>item.questionId)
  let params = {
    questionGroup:1,
    userAnswerRequestList
  }
  submitQuestionList(params).then((res:any)=>{
    localStorage.setItem("answerBatchNo",res.data)
    router.push("/answerDetail")
  })
 
}
//获取验证码
const obtain = ()=>{
  if(!vDate.phone){
    return Toast('请输入手机号');
  }
  if(!phoneReg.test(vDate.phone)){
    return Toast('请输入正确手机号');
  }
  setTimeoutInfo()
}
//定时器
const setTimeoutInfo = ()=>{
  const TIME_COUNT = 60;
  vDate.countNumber = 2
  vDate.flag = false
  if (!vDate.timer) {
    vDate.count = TIME_COUNT;
    vDate.timer = setInterval(() => {
    if (vDate.count > 0 && vDate.count <= TIME_COUNT) {
      vDate.count--;
      vDate.content = vDate.count+' s后获取';
      } else {
          vDate.content = '获取验证码';
          vDate.flag = true;
          clearInterval(vDate.timer);
          vDate.timer = null;
      }
      }, 1000)
  }
}
const radioClick = (i:number,item:any,val:any)=>{
  if(val.relationQuestionId!=null){
    setTimeout(()=>{
      vDate.questionId = val.relationQuestionId
      vDate.press = i+1
      vDate.next = -1
      vDate.isNext = val.relationQuestionId
      let index = vDate.answerList.findIndex((item:any)=>item.questionId == val.relationQuestionId)
      if(index==-1){
        vDate.answerList.forEach((item:any,v:number)=>{
          if(v>i){
            item.questionId = ""
            item.questionOptionId = ""
          }
        })
      }else{
        let arr = vDate.answerList.map((item:any,i:number)=>{
          return vDate.answerList[i].questionOptionId!=vDate.answerLists[i].questionOptionId
        })
        let indexs = arr.findIndex((item:any)=>item==true)
        if(indexs!=-1){
          vDate.answerList.forEach((item:any,v:number)=>{
            if(v>indexs){
              item.questionId = ""
              item.questionOptionId = ""
            }
          })
        }
      }
      clearTimeout()
    },300)
  }else{
    vDate.isAnswer = true
    vDate.next = 1
    vDate.isNext = null
  }
  vDate.answerList[i].questionId = item.questionId
  console.log(vDate.answerList,"vDate.answerList111")
  setTimeout(()=>{
    let index = vDate.dataList.findIndex(((item:any)=>item.questionId == val.relationQuestionId))
    if(index!=-1){
      let nextArr = vDate.dataList[index] //当前页项
      let flag = vDate.answerList[index].questionId
      if(flag){
        let arr = nextArr.optionList.filter((item:any)=>item.questionOptionId == vDate.answerList[index].questionOptionId)
        if(!arr[0].relationQuestionId){
          vDate.isAnswer = true
          vDate.next = 1
        }
      }
    }
  },500)

}
//获取题目
const queryList = ()=>{
  let params = {
    questionGroup:1
  }
  getQuestionList(params).then((res:any)=>{
    vDate.dataList = res.data
    res.data.forEach((item:any)=>{
      vDate.idList.push(item.questionId)
      vDate.answerList.push({
        questionId:'',
        questionOptionId:''
      })
    })
    vDate.questionId = res.data[0].questionId
    vDate.answerLists = JSON.parse(JSON.stringify(vDate.answerList))
  })  
}
onMounted(()=>{
  queryList()
})
</script>

看下题目的数据结构

 感兴趣的小伙伴可以自己动手试一试 看似简单的东西 里面很有多坑  有需求的可以私信我 免费获取全部代码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/48311.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux】文件权限的理解

不用心做一件事情&#xff0c;你永远不知道自己有多么的强大&#xff01; 文章目录一、shell命令以及运行原理(centos7下&#xff0c;shell为命令行解释器bash)1. 什么是shell(Kernel外层的软件层)&#xff1f;2. shell的交互方式存在意义3. windows GUI对比Linux shell(都是Ke…

算法: C# 中将 Dictionary 集合用作 Hashmap 等价类型

一.只出现一次的数字 1.1 题目描述 给你一个整数数组 nums &#xff0c;除某个元素仅出现 一次 外&#xff0c;其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。 示例 1&#xff1a; 输入&#xff1a;nums [2,2,3,2] 输出&#xff1a;3 示例 2&#…

Faster RCNN全文翻译

Abstract—State-of-the-art【最先进的】 object detection networks depend on region proposal algorithms to hypothesize【假设、推测】 object locations.Advances like SPPnet [1] and Fast R-CNN [2] have reduced the running time of these detection networks, expos…

赞叹AI的力量-TopazLabs 全家桶使用经历

一、Topaz Gigapixel AI 之前有用过日本的一个2x提升的在线网站服务waifu2x 是通过深度卷积神经网络来实现的&#xff0c;对于anime-style的图片效果是非常好的&#xff0c;使用过之后发现对于一些真实图片效果也不错&#xff0c;只是放大之后能明显的看到局部失真。 效果图&…

详解nginx的root与alias

文章目录1. 结论2. 详解root2.1 基本用法2.2 location的最左匹配原则2.3 index2.4 nginx location解析url工作流程2.5 末尾/3. 详解alias3.1 基本用法4. 特殊情况4.1 alias指定文件4.2 root指定文件nginx版本: 1.18.0 1. 结论 location命中后 如果是root&#xff0c;会把请求…

Anaconda、Conda、pip、Virtualenv的区别

一、Anaconda 1.1 简介 Anaconda是一个包含180的科学包及其依赖项的发行版本。其包含的科学包包括&#xff1a;conda, numpy, scipy, ipython notebook等。 二、Conda 2.1 简述 conda是包及其依赖项和环境的管理工具。 适用语言&#xff1a;Python, R, Ruby, Lua, Scala, …

什么是CRM系统,它如何支持客户营销管理?

简道云回款&销售排名看板什么是CRM控制系统&#xff0c;它怎样全力支持顾客网络营销管理工作? 顾客关系管理工作(CRM)是国际品牌用以培育与顾客关系的技术。这些应用软件系统意在协助产品销售和服务全权更有效地与顾客沟通交流。由于91%的雇员超过11人的企业使用CRM&…

Vue3 —— 利用vite+vue创建一个vue3项目

前言 本文主要讲解如何利用vitevue创建第一个项目以及vue3的基础知识点 一、创建一个vue3项目 这里我们主要介绍如何利用 vitevue3创建项目 1.有关vite Vite&#xff08;法语意为 "快速的"&#xff0c;发音 /vit/&#xff0c;发音同 "veet"&#xff09;是…

AWS Lambda函数实战

AWS Lambda函数实战 实战效果&#xff1a;开发一个函数&#xff0c;它会关注事件中的某个名字&#xff0c;并返回“Hello<名字>&#xff01;”。如果输入事件没有提供名字&#xff0c;则函数返回一个更加通用的问候语“Hello World&#xff01;”。 AWS Lambda函数实战A…

vue后台实现点击图片放大

需求&#xff1a; 点击小图可以放大&#xff0c;放大后&#xff0c;通过手势等比例放大缩小、左右切换图、旋转、关闭。由于element-ui版本较低不支持使用图片放大的image组件。 代码 父组件&#xff1a; <template><div><!-- 放大图 --><el-image-vie…

数商云供应链管理系统助力化工行业企业实现客户订单管理可视化

订单管理是现代企业商务业务的重要组成部分&#xff0c;可以帮助企业解决订单管理低效、混乱等问题。随着产业互联网时代的到来&#xff0c;越来越多企业放弃传统费时费力的手动操作&#xff0c;开始应用数字化的管理工具来提高企业订单管理的水平。这里以化工行业企业为例&…

一文详解,数据仓库、数据库、数据中台、数据湖的区别

数据时代&#xff0c;各行业的企业都已经开始通过数据库来沉淀数据&#xff0c;但是真的论起数据库、数据仓库、数据中台&#xff0c;还是新出现的数据湖&#xff0c;它们的概念和区别&#xff0c;可能知道的人就比较少了&#xff0c;今天我们详细来比较了解一下。 数据仓库是…

ArrayList 和 LinkedList 之间应该怎么选择

这篇文章是来自知乎上的一个问题。 相信很多人在面试时都被问过这个问题&#xff0c;然后一般回答&#xff1a;ArrayList在指定下标访问时快&#xff0c;LinkedList在插入/删除元素时快。 其实这是一种人云亦云的谬误。可能最初有人这么回答&#xff0c;然后不加验证地转来转…

猿如意开发工具|JetBrains GoLand

一、猿如意是什么&#xff1f; 是CSDN推出的桌面客户端&#xff0c;旨在为广大开发者提供效率工具、文档、代码等优质工具和内容&#xff0c;提升开发者的学习和工作效率&#xff0c;详情点击&#x1f449;【猿如意官网】。为了让更多开发者更好的认识、了解、使用猿如意中的每…

项目管理(如何进行项目质量管理)

需要进行的工作&#xff1a; 1、规划项目质量管理&#xff1a;识别项目及其可交付成果的质量要求和/或标准&#xff0c;并书面描述项目将如何证明 符合质量要求和/或标准的过程。 2、管理质量&#xff1a;管理质量是把组织的质量政策用于项目&#xff0c;并将质量管理计划转化…

蓝桥杯嵌入式cubeMX自动生成的gpio.c文件解析

文章目录前言一、如何生成gpio.c文件二、gpio.c内部实现总结前言 这篇文章将带大家了解一下cubeMX自动生成的gpio.c文件。 一、如何生成gpio.c文件 在LED这篇文章中我们配置了控制LED的GPIO引脚&#xff0c;选择了PD2和PC8 PC9这三个引脚&#xff0c;并且将他们都设置为了输…

数图互通高校房产管理系统——住房管理

1、住房管理 1.1 住房档案 住房模块的管理主要是针对学校的承租住宅和已售住宅的管理&#xff0c;用于登记已售住宅的产权人信息&#xff0c;记录承租住宅的租赁起止日期、月租金等基本信息。 支持住房的坐落信息、楼栋、房间信息的维护。坐落位置主要维护校区编号、校区名称…

说明白正反向代理,以及Nginx和Gunicorn

一&#xff1a;什么是Nginx Nginx的产生 没有听过Nginx&#xff1f;那么一定听过它的"同行"Apache吧&#xff01;Nginx同Apache一样都是一种WEB服务器。基于REST架构风格&#xff0c;以统一资源描述符(Uniform Resources Identifier)URI或者统一资源定位符(Uniform …

图像质量评价指标metrics:PSNR 、SSIM、LPIPS

一、PSNR&#xff08;峰值信噪比&#xff09; 1.定义 是基于对应像素点间的误差&#xff0c;即基于误差敏感的图像质量评价&#xff0c;由于并未考虑到人眼的视觉特性&#xff08;人眼对空间频率较低的对比差异敏感度较高&#xff0c;人眼对亮度对比差异的敏感度较色度高&…

HTTP协议中的Cookie 和 Session

Cookie Session一 Cookie1.Cookie是什么?2.Cookie的工作机制二 Session1.Session的工作机制三 Cookie 和 Session 的区别一 Cookie 1.Cookie是什么? Cookie是一组键值对保存在客户端&#xff0c;服务器给浏览器的一组键值对(Sessionidxxxxxxx)通过Cookie来传递给客户端&…