完成大我 发表于 2023-1-17 17:58

【vue3】孩子一岁半了,压力很大,给她开发一个学习平台吧,持续更新

本帖最后由 完成大我 于 2023-2-2 18:27 编辑

1.项目背景楼主回老家的国企工作之后一直很无聊,一周的工作2天做完,写ppt比写代码多,再这样下去就废了。孩子一岁半了,还有一年半就上幼儿园了,给她开发一个学习平台吧,顺便学学前端技术,楼主是理科生,比较注重理科的学习,学习平台优先侧重于理科需求,当然后面会根据实际需求去不断完善平台。
2.需求
| 需求编号 | 需求名称 | 需求描述                                                   | 需求备注 |
| -------- | -------- | ------------------------------------------------------------ | -------- |
| 1      | 算术题   | 支持加减乘除及混合运算的自动生成,及批改;<br />支持整数、小数、分数等各种类型数字的生成条件;<br />支持数字范围、多参运算的生成条件。 |          |
| 2      | 应用题   | 常见题型概念、分析、样例;<br />应用题自动生成及批改;       |          |
| 3      | 公式大全 | 常见公式的增删改查;<br />便于常用公式的快速检索,按名称、分类、内容等条件模糊搜索; |          |
| 4      | 题库管理 | 非典型题库的增删改查;<br />也用于自动生成非标准题目的随机抽取; |          |
| 5      | 知识库   | 包含小学数学课程的全部知识点;<br />支持按年级、标题(模糊)、分类、内容(模糊)搜索。 |          |
| 6      | 待规划   | ....                                                         |          |
3.技术方案
前端:vue3.0+typeScript+ElentmentPlus+vatex
楼主是后端工程师,不太懂前端,选择主流易上手的vue,typeScript的语法接近后端也很容易上手,ElentmentUI是开源的组件库,丰富全面美观,开箱即用,vatex是公式组件,用于页面上更好的展示公式。
本文对于通用功能,比如系统登录,前端动态路由等功能实现不做赘述。只专注于需求核心代码的介绍。

后端:SpringBoot+mybatisPlus+poi-tl
考虑到部署问题,楼主没太多钱买服务器,能用前端实现的功能就用前端实现,后端主要用于必要数据库的增删改查操作,还有一些前端不易实现的功能,比如office文档操作,根据模板生成文档等功能。

4.具体实现
4.1 应用题
页面效果

每个问题类型对应一个子页面组件,使用<component :is="currentName"></component>组件,根据左侧问题类型选择树选项动态的加载组件。

应用题模块页面代码:
<template>
    <div style="float:left;">
      <dir><el-tree ref="treeRef" default-expand-all :data="typeTree" :props="props" :height="800"
                @node-click="handleNodeClick" /></dir>
    </div>
    <div style="float:left;">
      <component :is="currentName"></component>
    </div>
</template>

<script lang="ts">
import { defineComponent, ref, reactive } from 'vue'
import { questionTypeTreeData } from '@/type/treeData'
import { ElTree } from 'element-plus'
import ChickenRabbitCage from '@/components/wordproblem/ChickenRabbitCage.vue'
import Unification from "@/components/wordproblem/Unification.vue"

export default defineComponent({
    components: { ChickenRabbitCage, Unification},
    setup() {
      const treeRef = ref<InstanceType<typeof ElTree>>()
      const typeTree = reactive(questionTypeTreeData)
      const props = reactive({
            value: 'value',
            label: 'label',
            children: 'children',
      })

      const currentName = ref('')
      const handleNodeClick = () => {
            currentName.value = treeRef.value!.getCurrentNode().value
            console.log(currentName.value);
            

      }


      return {
            typeTree,
            props,
            handleNodeClick,
            treeRef,
            currentName
      }
    }
})
</script>

<style lang="scss" scoped>
.el-tree {
    width: 200px;
}
</style>
归一问题子页面代码:
<template>
    <h2>归一问题</h2>
    <div>
      <div>
            <el-card class="box-card">
                <template #header>

                  <div class="card-header">
                        <h3>问题背景</h3>
                  </div>
                </template>
                <p> 归一问题是指根据已知条件,在解题时要先求出一份是多少(归一,单一量),如单位时间内的工作量,单位面积的产量、商品的单价、单位时间内所行的路程等,
                  然后再求出所求问题的应用题叫归一问题。归一问题分为正归一问题和反归一问题。
                </p>
                <p>
                  归一问题可分为正归一问题和反归一问题。正归一是指,已知某物数量和总量(比如总价),求新的数量对应的总量是多少。反归一问题是指,已知某物数量和总量,
                  求新的总价对应的某物数量是多少。
                </p>
            </el-card>
      </div>
      <div>
            <el-card class="box-card">
                <template #header>

                  <div class="card-header">
                        <h3>解题思路</h3>
                  </div>
                </template>
                <h4>正归一问题</h4>
                <p>总量/数量=单一量</p>
                <p>单一量*新的数量=新的总量</p>
                <p>综合式:总量/数量*新的数量=新的总量</p>

                <h4>反归一问题</h4>
                <p>总量/数量=单一量</p>
                <p>新的总量/单一量=新的数量</p>
                <p>综合式:新的总量/(总量/数量)=新的数量</p>

                <h4>问题变种</h4>
                <p>数量可以是两个参数甚至更多的参数,比如数量参数有n个,有一组已知数量参数及对应的总量,求新的一组参数对应的总量;
                  或有一组已知数量参数及对应的总量,求新的总量,及新的一组(n-1)个参数,求未知的那个参数。</p>
            </el-card>
      </div>

      <div>
            <el-card class="box-card">
                <template #header>

                  <div class="card-header">
                        <h3>例题解答</h3>
                  </div>
                </template>
                <p>学校买6个同样的篮球共用468元,照这样计算,1014元可以买多少个这样的篮球?</p>
                <p>解:</p>
                <p>(1)这是典型的反归一问题,单一量 = 468÷6 = 78(元/个) </p>
                <p>(2)用新的总量求新的数量,新的数量 = 1014 ÷ 78 = 13(个)</p>
                <p>答:1014元可以买13个这样的篮球</p>
            </el-card>

      </div>

      <!-- 问题自动生成 -->
      <div class="d-button" @click="drawerStatus = true">
            <el-button>问题生成</el-button>
      </div>
      <div>
            <el-drawer v-model="drawerStatus" @close="closeDrawer" size="40%">
                <template #header>
                  <h4>归一问题自动生成</h4>
                </template>
                <template #default>
                  <div>
                        <el-button color="green" @click="generateAQuestion" class="d-button">一键生成</el-button>
                  </div>
                  <!-- 问题展示 -->
                  <div>
                        <el-card v-show="answerStatus">
                            <p>
                              {{ questionData.problem }}
                            </p>
                        </el-card>
                  </div>
                  <!-- 解答区 -->
                  <div>
                        <el-card v-show="answerStatus">
                            <template #header>

                              <div class="card-header">
                                    <h4>题解</h4>
                              </div>
                            </template>
                            <p>单一量为:{{ questionData.totalKnown }} ÷ {{ questionData.numberKnown }} =
                              <span>
                                    <el-input-number v-model="userAnswer.singleValue" class="mx-4" />
                              </span>
                              {{ questionData.totalUnit }}/{{ questionData.numberUnit }};
                            </p>
                            <p v-if="questionData.type == '1'">
                              <span>
                                    <span>
                                        则新的数量{{ questionData.numberNew }}{{questionData.numberUnit}}对应的新的总量是: {{ questionData.numberNew }} ×
                                        {{ userAnswer.singleValue }} =
                                    </span>
                                    <el-input-number v-model="userAnswer.userTotalNew" class="mx-4" />
                                    {{ questionData.totalUnit }}
                              </span>
                            </p>
                            <p v-if="questionData.type == '2'">
                              <span>
                                    <span>
                                        则新的总量{{ questionData.totalNew }}{{ questionData.totalUnit }}对应的数量是:{{ questionData.totalNew }} ÷
                                        {{ userAnswer.singleValue }} =
                                    </span>
                                    <el-input-number v-model="userAnswer.userNumberNew" class="mx-4" />
                                    {{questionData.numberUnit}}
                              </span>
                            </p>
                            <p v-if = "questionData.type == '1'">
                              {{
                                    questionData.answerTemplate.replace("totalNew", String(userAnswer.userTotalNew)).replace("numberNew", String(questionData.numberNew))
                              }}
                            </p>
                            <p v-else>
                              {{
                                    questionData.answerTemplate.replace("numberNew", String(userAnswer.userNumberNew)).replace("totalNew", String(questionData.totalNew))
                              }}
                            </p>

                        </el-card>
                        <!-- 批改区 -->
                        <div v-show="answerStatus">
                            <div style="float:right;">
                              <el-button @click="correct" class=".d-button">批改</el-button>
                            </div>
                        </div>
                        <div v-show="correctStatus">
                            <el-card>
                              <div>
                                    <el-tag class="ml-2" type="success" v-if="isCorrect">正确</el-tag>
                                    <el-tag class="ml-2" type="warning" v-else>错误</el-tag>
                              </div>
                              <div>
                                    <p>{{ questionData.answer    }}</p>
                              </div>
                            </el-card>


                        </div>

                  </div>
                </template>

            </el-drawer>
      </div>
    </div>
</template>

<script lang="ts">
import { defineComponent, reactive, toRefs } from 'vue'
import { UnificationQuestionGenerator } from '@/function/wordQuestionGenP1'

export default defineComponent({
    setup() {
      const data = reactive({
            drawerStatus: false,
            answerStatus: false,
            correctStatus: false,
            isCorrect: false,
            questionData: {
                single: 0,
                numberKnown: 0,
                totalKnown: 0,
                numberNew: 0,
                totalNew: 0,
                problem: "",
                answer: "",
                type: "",
                prolemTemplate: "",
                answerTemplate: "",
                numberUnit: "",
                totalUnit: ""
            },
            userAnswer: {
                singleValue: 0,
                userNumberNew: 0,
                userTotalNew: 0
            }
      })
      const closeDrawer = () => {
            data.drawerStatus = false
            data.answerStatus = false
            data.correctStatus = false
            data.isCorrect = false
      }
      const generateAQuestion = () => {
            data.correctStatus = false
            data.isCorrect = false
            // 用户答案初始化
            data.userAnswer ={
                singleValue: 0,
                userNumberNew: 0,
                userTotalNew: 0
            }
            data.questionData = UnificationQuestionGenerator()
            data.answerStatus = true
      }

      // 批改函数
      const correct = () => {
            data.correctStatus= true
            if(data.questionData.type == '1'){
                if(data.questionData.totalNew == data.userAnswer.userTotalNew) data.isCorrect = true
            }
            else {
                if(data.questionData.numberNew == data.userAnswer.userNumberNew) data.isCorrect = true
            }
      }



      return {
            ...toRefs(data),
            closeDrawer,
            generateAQuestion,
            correct
      }
    }
})
</script>

<style scoped>
.box-card {
    width: 1200px;
}

h2 {
    color: rgb(78, 77, 77);
}

h3 {
    color: burlywood;
}

p {
    text-indent: 25px
}
</style>

核心ts函数,问题的自动生成:
//归一问题
export interface UnificationQuestionData {
    single: number
    numberKnown: number
    totalKnown: number
    numberNew: number
    totalNew: number
    problem: string
    answer: string
    type: string
    prolemTemplate: string
    answerTemplate: string
    numberUnit: string
    totalUnit: string
}
interface Problem {
    problem: string
    answer: string
    type: string
    magnitude: number
    numberUnit: string
    totalUnit: string
}
const UnificationProblems: Array<Problem> = [
    {
      'problem': "一列火车numberKnown小时行驶totalKnown千米,照这样算,numberNew小时行驶多少千米?",
      'answer': "答:numberNew小时行驶totalNew千米",
      'type': '1',
      'numberUnit': '小时',
      'totalUnit': '公里',
      'magnitude': 300
    },
    {
      'problem': "学校买numberKnown个同样的篮球共用totalKnown元,照这样计算,totalNew元可以买多少个这样的篮球?",
      'answer': "答:totalNew元可以买numberNew个这样的篮球",
      'type': '2',
      'numberUnit': '个',
      'totalUnit': '元',
      'magnitude': 100
    },
    {
      'problem': "小红骑车numberKnown分钟骑行totalKnown米,照这样的速度她从家到学校骑行了numberNew分钟,小红家到学校有多少米?",
      'answer': "答:小红家到学校有totalNew米",
      'type': '1',
      'numberUnit': '分钟',
      'totalUnit': '米',
      'magnitude': 500
    },
    {
      'problem': "一只小蜗牛numberKnown分钟爬行totalKnown分米,照这样的速度,numberNew分钟爬行多少分米?",
      'answer': "答:numberNew分钟爬行了totalNew分米",
      'type': '1',
      'numberUnit': '分钟',
      'totalUnit': '分米',
      'magnitude': 10
    },
    {
      'problem': "一艘轮船numberKnown小时航行totalKnown千米,照这样的速度,继续航行totalNew千米,共需多少小时?",
      'answer': "答:继续航行totalNew千米,共需numberNew小时",
      'type': '2',
      'numberUnit': '小时',
      'totalUnit': '千米',
      'magnitude': 50
    }

]
export const UnificationQuestionGenerator = () => {
    const result: UnificationQuestionData = {
      single: 0,
      numberKnown: 0,
      totalKnown: 0,
      numberNew: 0,
      totalNew: 0,
      problem: "",
      answer: "",
      type: "",
      prolemTemplate: "",
      answerTemplate: "",
      numberUnit: "",
      totalUnit: ""
    }
    const index = random(0, UnificationProblems.length - 1)
    result.prolemTemplate = UnificationProblems.problem
    result.answerTemplate = UnificationProblems.answer
    result.numberUnit = UnificationProblems.numberUnit
    result.totalUnit = UnificationProblems.totalUnit
    result.type = UnificationProblems.type
    result.single = random(Math.ceil(UnificationProblems.magnitude / 5), UnificationProblems.magnitude)
    result.numberKnown = random(2, 10)
    result.totalKnown = result.single * result.numberKnown
    result.numberNew = random(11, 20)
    result.totalNew = result.single * result.numberNew




    result.problem = result.prolemTemplate.replace('numberKnown', String(result.numberKnown))
    result.problem = result.problem.replace('totalKnown', String(result.totalKnown))
    result.problem = result.problem.replace('numberNew', String(result.numberNew))
    result.problem = result.problem.replace('totalNew', String(result.totalNew))

    result.answer = result.answerTemplate.replace("numberNew", String(result.numberNew))
    result.answer = result.answer.replace('totalNew', String(result.totalNew))

    return result
}
其中UnificationQuestionData 是定义了归一问题,问题模型的数据格式,即题目中涉及到的所有字段;
Problem是定义了问题模板库的数据格式,问题模板字段包括,problem--问题模板,answer答案模板,type问题类型(区分正归一,反归一),numberUnit数量单位,totalUnit总量单位,magnitude数据量级,用于生成限定合理的随机数范围;
UnificationProblems是问题模板库,生成问题时,从UnificationProblems里随机抽取一条作为模板。
生成的过程为:

[*]数据初始化
[*]随机抽取一个模板
[*]根据magnitude生成随机数,更新返回数据
[*]将问题模板、答案模板内的标志符替换为生成的随机数
[*]返回生成的问题数据

页面效果:

今天就到这里,持续码代码中,后面有时间更新其他章节。


https://static.52pojie.cn/static/image/hrline/4.gif

典型的应用题型知识点,题目自动生成及批改,实现的思路都与归一问题实现类似,小学节点典型的问题有三十种,所有应用题都可以抽象为这三十种的一种。目前完成归一问题、归总问题、鸡兔同笼问题三个子组件的开发,其他题型会持续完善。

4.2.算术题自动生成
算术题的自动生成及批改功能,包括生成条件栏、问题列表、批改按钮及分数展示三部分。生成条件包括问题类型、题目数量、数字范围;问题列表展示问题,作答区,及批改结果;批改后批改按钮下侧会自动展示分数。
代码:
<template>
    <div>
      <div class="filter-condition">
            <el-form :inline="true" ref="ruleFormRef" status-icon :model="filterdata" :rules="rules"
                class="demo-form-inline">

                <el-form-item label="问题类型" prop="type" class="inputitem">
                  <el-select v-model="filterdata.type" placeholder="问题类型">
                        <el-option label="加法" value="+" />
                        <el-option label="减法" value="-" />
                        <el-option label="加减混合" value="+-" />
                        <el-option label="乘法" value="×" />
                        <el-option label="整数除法" value="÷" />
                        <el-option label="分数" value="/" />
                  </el-select>
                </el-form-item>
                <el-form-item label="题目数量" prop="quantity" class="inputitem">
                  <el-select v-model="filterdata.quantity" placeholder="题目数量">
                        <el-option label="20" value="20" />
                        <el-option label="40" value="40" />
                        <el-option label="60" value="60" />
                  </el-select>
                </el-form-item>
                <el-form-item label="数字范围" prop="numberRange" class="inputitem">
                  <el-select v-model="filterdata.numberRange" placeholder="问题范围">
                        <el-option label="0~9" value="0,9" />
                        <el-option label="0~19" value="0,19" />
                        <el-option label="0~29" value="0,29" />
                        <el-option label="0~39" value="0,39" />
                        <el-option label="0~49" value="0,49" />
                        <el-option label="0~59" value="0,59" />
                        <el-option label="0~69" value="0,69" />
                        <el-option label="0~79" value="0,79" />
                        <el-option label="0~89" value="0,89" />
                        <el-option label="0~99" value="0,99" />
                  </el-select>
                </el-form-item>


                <el-form-item>
                  <el-button type="primary" @click="genQuestions(ruleFormRef)">生成</el-button>
                </el-form-item>
                <el-form-item>
                  <!-- <el-button type="primary" @click="exportQuestion">导出</el-button> -->
                </el-form-item>
            </el-form>
      </div>


      <div class="question">
            <div style="float:left;">
                <el-table ref="tableRef" row-key="date" :data="generatedData.slice(0, filterdata.quantity / 2)"
                  style="width: 100%" :header-cell-style="{ 'background-color': '#F1F4FF', 'text-align': 'center' }">
                  <!-- <el-table-column prop="content" label="题目" width="240" /> -->

                  <el-table-column label="题目" width="240">
                        <template #default="scope">
                            <vue-latex :expression="scope.row.content" display-mode />
                        </template>
                  </el-table-column>

                  <el-table-column label="答案" width="180">
                        <template #default="scope">
                            <el-input v-model="scope.row.solve" size="small" placeholder="请输入答案" />
                        </template>
                  </el-table-column>
                  <el-table-column label="是否正确" width="180">
                        <template #default="scope">
                            <div v-if="isClickCorrectButton">
                              <el-tag key="正确" class="mx-1" v-if="scope.row.isCorrect" closable
                                    type="success">正确</el-tag>
                              <el-tag key="错误" class="mx-1" v-else closable type="warning">错误</el-tag>
                            </div>
                        </template>
                  </el-table-column>
                </el-table>
            </div>
            <div style="float:left;">
                <el-table ref="tableRef" row-key="date"
                  :data="generatedData.slice(filterdata.quantity / 2, filterdata.quantity)" style="width: 100%"
                  :header-cell-style="{ 'background-color': '#F1F4FF', 'text-align': 'center' }">
                  <el-table-column label="题目" width="180">
                        <template #default="scope">
                            <vue-latex :expression="scope.row.content" display-mode />
                        </template>
                  </el-table-column>

                  <el-table-column label="答案" width="240">
                        <template #default="scope">
                            <el-input v-model="scope.row.solve" size="small" placeholder="请输入答案" />
                        </template>
                  </el-table-column>
                  <el-table-column label="是否正确" width="180">
                        <template #default="scope">
                            <div v-if="isClickCorrectButton">
                              <el-tag key="正确" class="mx-1" v-if="scope.row.isCorrect" closable
                                    type="success">正确</el-tag>
                              <el-tag key="错误" class="mx-1" v-else closable type="warning">错误</el-tag>
                            </div>

                        </template>
                  </el-table-column>
                </el-table>
            </div>
            <div style="float:left;" class="correct">
                <el-button @click="correctCal" color="green">批改</el-button>
                <div>
                  <el-rate v-if="scoredata.ismark" v-model="scoredata.score" show-score text-color="#ff9900" disabled
                        allow-half="true" size="large" :score-template="scoredata.score * 20 + '分'"
                        :colors="['#CC3300', '#FFFF99', '#66FF33']" />
                </div>
            </div>


      </div>
      <div>

      </div>
    </div>
</template>

<script lang="ts">
import { defineComponent, reactive, toRefs, ref } from 'vue'
import { GenData, FilterConditionInterface } from '@/type/questionGener'
import { QuestionInterface } from '@/type/questionQueryer'
import type { FormInstance } from 'element-plus'
import { random } from '@/function/random'
import { deepClone } from '@/function/deepClone'
import { divisors, maxdivisor } from '@/function/divisors'
export default defineComponent({
    setup() {
      const ruleFormRef = ref<FormInstance>()

      const data = reactive(new GenData())
      let isClickCorrectButton = ref(false)
      let scoredata = reactive({
            score: 0,
            ismark: false
      })
      const rules = {
            type: [
                {
                  required: true,
                  message: "请选择问题类型",
                  trigger: "blur",
                }
            ],
            quantity: [
                {
                  required: true,
                  message: "请输入问题数量",
                  trigger: "blur",
                }
            ],
            numberRange: [
                {
                  required: true,
                  message: "请选择数字范围",
                  trigger: "blur",
                }
            ]
      }
      // 生成一个问题

      const generateAQuestion = (condition: FilterConditionInterface) => {
            const question: QuestionInterface = {
                title: "",
                type: "",
                content: "",
                answer: "",
            }
            let num1 = random(condition.numberRange, condition.numberRange)
            const num2 = random(condition.numberRange, condition.numberRange)
            let num3, num4, div, max_divisor
            switch (condition.type) {
                case "+":
                  question.content = num1 + "+" + num2;
                  question.answer = num1 + num2
                  break;
                case "-":
                  num3 = random(condition.numberRange, num1)
                  question.content = num1 + "-" + num3;
                  question.answer = num1 - num3
                  break;
                case "×":
                  question.content = num1 + "×" + num2;
                  question.answer = num1 * num2
                  break;
                case "÷":
                  num1 = random(1, condition.numberRange)
                  div = divisors(num1)
                  div.push(1)
                  div.push(num1)
                  console.log(div);

                  num3 = div
                  question.content = num1 + "÷" + num3;
                  question.answer = num1 / num3
                  break;
                case "/+":
                  num3 = random(1, condition.numberRange)
                  num4 = random(1, condition.numberRange)
                  question.content = '\\frac{' + num1 + '}{' + num3 + '}' + '+' + '\\frac{' + num2 + '}{' + num4 + '}'
                  max_divisor = maxdivisor(num1 * num4 + num2 * num3, num3 * num4)
                  question.answer = (num1 * num4 + num2 * num3) / max_divisor + '/' + (num3 * num4) / max_divisor
                  break
                case "/-":
                  num3 = random(1, condition.numberRange)
                  num4 = random(1, condition.numberRange)
                  if (num1 * num4 > num2 * num3) {
                        question.content = '\\frac{' + num1 + '}{' + num3 + '}' + '-' + '\\frac{' + num2 + '}{' + num4 + '}'
                        max_divisor = maxdivisor(num1 * num4 + num2 * num3, num3 * num4)
                        question.answer = (num1 * num4 - num2 * num3) / max_divisor + '/' + (num3 * num4) / max_divisor
                  }
                  else {
                        question.content = '\\frac{' + num1 + '}{' + num3 + '}' + '-' + '\\frac{' + num2 + '}{' + num4 + '}'
                        max_divisor = maxdivisor(num1 * num4 + num2 * num3, num3 * num4)
                        question.answer = (num2 * num3 - num1 * num4) / max_divisor + '/' + (num3 * num4) / max_divisor
                  }

                  break
                default:
                  break

            }
            return question
      }


      //问题生成入口
      const genQuestions = (formEl: FormInstance | undefined) => {
            //清除判题展示
            isClickCorrectButton.value = false
            scoredata.ismark = false
            if (!formEl) return
            formEl.validate((valid) => {
                if (valid) {
                  //问题生成
                  const operator = ['+', "-", "/+", "/-"]
                  let filter = deepClone(data.filterdata)
                  data.generatedData = []

                  filter.numberRange = data.filterdata.numberRange.split(',') as Array<number>
                  for (var _i = 0; _i < data.filterdata.quantity; _i++) {
                        //混合运算处理
                        if (data.filterdata.type == '+-') {
                            filter.type = operator
                        }
                        if (data.filterdata.type == '/') {
                            filter.type = operator
                        }
                        data.generatedData.push(generateAQuestion(filter))
                  }
                } else {
                  console.log('error submit!')
                  return false
                }
            })


      }
      //判题函数
      const correctCal = () => {
            isClickCorrectButton.value = true
            let correct_count = 0
            data.generatedData.forEach((val, idx, array) => {
                if (val.answer == (val.solve as number)) {
                  val.isCorrect = true
                  correct_count++
                }
                else {
                  val.isCorrect = false
                }
            });
            scoredata.ismark = true
            scoredata.score = 5 * correct_count / data.filterdata.quantity

      }
      return {
            ruleFormRef,
            ...toRefs(data),
            genQuestions,
            correctCal,
            isClickCorrectButton,
            rules,
            scoredata
      }
    }
})
</script>

<style scoped>
el-result {
    height: 20px;
}

.correct {
    margin-left: 20px;
    margin-right: 20px;
}
</style>
页面效果:


欢迎大家积极提出好的建议与点子,有时间楼主再更新

https://static.52pojie.cn/static/image/hrline/2.gif
https://static.52pojie.cn/static/image/hrline/2.gif

为了方便观看,新开贴,古诗词模块更新:【vue3】给女儿开发的学习平台之古诗词篇~服务部署成功
(出处: 吾爱破解论坛)
5.服务地址
楼主花了70块买了个垃圾云服务器,卡的呀批,终于把服务部署起来了,楼主都是利用工作之余写一下,目前比较简陋,还望海涵;
爬取的视频数据,可能因为关键词不准,有些古诗的视频对不上号,后面楼主会优化关键词重新爬取,目前只有唐诗300首,古诗也会继续丰富
上地址http://1.15.179.113/

zoro8 发表于 2023-1-17 18:33

自己的体会,太早的提前教学会毁了孩子!别听什么“别输在起跑线上“,实际上有这样想法的人已经输了!!!!!!

hjxhjxjx 发表于 2023-1-17 18:18

才一岁半啊,你怎么下得去手的啊!:rggrg

有礼貌的牛 发表于 2023-1-17 18:05

孩子:你问过我意见啦吗{:301_985:}

lxq8432 发表于 2023-1-17 18:59

工具很好。

=======================

小娃娃,多动手搭搭积木

可以看娃娃书,不要教其他内容
特别不要去练写字

要培养孩子阅读的习惯
这个家长要花大量的时间

blackdarks 发表于 2023-1-17 18:29

才一岁半啊!你就做个人吧,孩子能开开心心的童年没几年

QZMASE 发表于 2023-1-17 18:28

楼主的逻辑是,孩子压力很大,所以给他多做点题不让他想太多吗?

artedu 发表于 2023-1-17 19:35

楼主,我不懂技术,但是从你这个图来看,感觉你是在给大学生做平台。小孩子学东西完全是靠兴趣,因此,很多奖励之类的评价就很关键了。在玩中学,在学中玩。说的就是这了。

jisoo 发表于 2023-1-20 10:20

孩子:哒 口羊

眷恋 发表于 2023-1-17 18:07

期待成品

shujia2112 发表于 2023-1-17 18:02

{:1_921:}}666

思念曹操 发表于 2023-1-17 18:11

楼主真有远见,我都是随遇而安

troybug 发表于 2023-1-17 18:27

有很多早教系统
页: [1] 2 3 4 5 6 7 8 9 10
查看完整版本: 【vue3】孩子一岁半了,压力很大,给她开发一个学习平台吧,持续更新