vue2 + element-ui 实现试卷在线打分 上传的页面(移动端)

最近两个做了一个展示试卷信息,选项等,并在前端页面打分 把分数与选项传进数据库,并且可以点击回显。

页面功能:我的试卷是代表着用户已做完的试卷,点击会弹出组件展示已做完试卷的信息(测试数据就放了一个,他里面还集成了下拉加载)

在首页点击继续考试或者开始考试弹出做题组件

接下来上代码

(后台返回的测试数据)

首页html代码

<template>
    <div class="net">
        <div v-if="isItem">//isitem 用来首页与试卷详情的显示切换
            <div v-if="isGo">// isGo 用来首页与考试页面的显示切换
                <el-card class="box-card" :body-style="{ padding: '10px' }">
                    <div slot="header" class="clearfix">
                        <span style="font-size: 20px;">我的试卷:</span>
                    </div>
                    <div>
                        <mescroll-uni ref="mescrollRef" @init="mescrollInit" :down="downOption" @up="upCallback"
                            :fixed="false">
                            <div v-show="!isMyShow" @click="itemClick(i)" v-for="i in myList" >
                                <el-card class="box-card-item">
                                    <div slot="header" class="clearfix-header">
                                        <span>{{ i.Title }}</span><span>测试结果:<span class="xu">{{ i.Result
                                        }}</span></span> 
                                    </div>
                                    <div class="date">得分:<span class="xu">{{ i.Score}}</span></div>
                                    <div class="date"> <span class="bodyname">考试人:<span class="xu">{{ i.F_CreatorUserId}}</span></span> 
                                        <div class="date">交卷时间:<span class="xu">{{ i.F_LastModifyTime
                                        }}</span></div>
                                    </div>
                                </el-card>
                            </div>

                        </mescroll-uni>
                    </div>
                </el-card>
            </div>
            // examination组件考试组件
            <examination @isGoShow="setFn" v-else :paperItem="paperItem" :newPaper="newPaper" :form="form" :config="config"
                :id="id" @setText="getPaperrList"></examination>
            <el-button class="parserbtn" v-if="isGo" type="primary" round @click="goExamination()"
                style="margin-bottom: 15px;">{{ text ? '开始考试'
                    : '继续考试' }}</el-button>
        </div>
        // completedItem详情组件
        <completedItem v-else @isItem="isItem = !isItem" :completedItem="completedItem" :formItem="formItem">
        </completedItem>
    </div>
</template>

script部分

需要注意的地方因为有个业务功能,需要保存试题,所以如果点击开始考试但是没有做完就得变成开始考试且继续做那张试卷

然后代码中有很多在处理格式,因为接口是我们公司低代码平台生成的,所以格式返回的都是json字符串,所以多了很多处理格式的地方,包括提交post接口也要转化成json字符串,所以很麻烦,不过你们应该可以跟后端沟通

<script>
import { getPaperrList, getPaperrItem, getPaperrNewItem, getPaperrItemMore } from "@/api/apply/paper"
import examination from "./examination.vue"
import completedItem from "./completedItem.vue"
import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js";
export default {
    mixins: [MescrollMixin],
    props: ['config'],
    components: { examination, completedItem },
    data() {
        return {
            name: 'dynamicPaper',
            isGo: true,
            isMyShow: false,
            isItem: true,
            myList: [],
            todoList: [],
            paperItem: [],
            completedItem: {},
            form: {
                res: [],
            },
            formItem: {
                res: [],
            },
            downOption: {
                use: false,
                isLock: false
            },
            datas: {
                currentPage: 1,
                menuId: '397890880037468677',
                pageSize: 10,
                queryJson: "",
                sidx: "",
                sort: "desc",
                superQueryJson: ""
            },
            newdatas: {
                data: {
                    Title: "试卷1",
                    F_CreatorUserId: "",
                    F_CreatorTime: "",
                    F_LastModifyTime: "",
                    tableField110: [],
                    id: "",
                    flowId: ""
                },
                id: ''
            },
            newPaper: {},
            id: '',
            text: true
        }
    },
    created() {
    },
    // 监听未完成考试数组
    watch: {
        todoList: {
            handler(newVal, oldVal) {
                if (!newVal.length) {
                    this.text = true
                } else {
                    this.text = false
                }
            },
            immediate: true
        }
    },

    methods: {
        // 检测未完成试卷
        getweiList() {
            let obj = { ...this.datas }
            obj.pageSize = 999
            getPaperrList(obj, this.config.flowId).then(({ data }) => {
                this.todoList = data.list.filter(item => { return item.Score==0 })
            })
        },
        // 已完成试卷点击详情
        itemClick(i) {
            this.myList = []
            getPaperrItem(this.config.flowId, i.F_Id).then(({ data }) => {
                this.completedItem = JSON.parse(data.data)
                this.completedItem.tableField110.forEach((item, ind) => {
                    // 处理选项格式 
                    this.completedItem.tableField110[ind].Options = eval(item.Options)
                })
                this.completedItem.tableField110.forEach((it, i) => {
                    if (this.completedItem.tableField110[i].QuestionType == 2) {
                        // 处理多选题正确答案格式
                        this.completedItem.tableField110[i].Answer = eval(this.completedItem.tableField110[i].Answer).sort().toString()
                        // 处理考生答案选项格式
                        if(!it.ExamineeAnswer) return
                        let arr = it.ExamineeAnswer.split(',')
                        arr.forEach((item, index) => {
                            arr[index] = parseInt(arr[index])
                        })
                        this.formItem.res[i] = arr
                    } else {
                        this.formItem.res[i] = parseInt(it.ExamineeAnswer)
                    }
                });

                this.isItem = !this.isItem
                document.documentElement.scrollTop = 0
            })
        },
        // 继续/开始考试
        goExamination() {
            this.myList = []
            // 继续考试
            if (this.todoList.length) {
                this.getPaperrItem(this.config.flowId, this.todoList[0].id)
            } else {
                // 开始考试
                this.newdatas.data = JSON.stringify(this.newdatas.data)
                let timestamp = Date.parse(new Date()) / 1000;
                getPaperrNewItem(this.config.flowId, timestamp, this.newdatas).then((res) => {
                    this.getPaperrItem(this.config.flowId, res.data.Id)
                })
            }
            document.documentElement.scrollTop = 0
            this.isGo = !this.isGo
        },
        // 获取试卷详情请求
        getPaperrItem(flowId, dataId) {
            getPaperrItem(flowId, dataId).then(({ data }) => {
                console.log(data);
                this.id = data.id
                this.newPaper = JSON.parse(data.data)
                this.paperItem = JSON.parse(data.data).tableField110
                this.paperItem.forEach((item, ind) => {
                    // 处理选项格式 
                    this.paperItem[ind].Options = eval(item.Options)
                    if (item.QuestionType == 2) {
                        // 处理多选题答案格式 json转化数组
                        this.paperItem[ind].Answer = JSON.parse(this.paperItem[ind].Answer)
                    }
                    // 处理判断题答案格式
                    if (item.QuestionType == 3) {
                        this.paperItem[ind].Answer = this.paperItem[ind].Answer.slice(0, this.paperItem[ind].Answer.length - 1).slice(1)
                    }
                })
                this.crFormres(this.paperItem, this.form.res)
            }).catch(err => {
                this.$refs.uToast.show({
                    title: err,
                    type: 'error',
                })
            })
        },
        // 处理传入子组件格式
        crFormres(item, res) {
            item.forEach((it, i) => {
                if (item[i].QuestionType == 2) {
                    res[i] = []
                } else {
                    res[i] = ''
                }
                console.log('处理了');
            });
        },
        setFn() {
            this.isGo = true
            this.getweiList()
        },
        // 下拉加载
        upCallback(page) {
            this.getweiList()
            this.datas.currentPage = page.num
            getPaperrList(this.datas, this.config.flowId).then(({ data }) => {
                this.myList.push(...data.list.filter(item => { return item.Score>0 }))
                // this.todoList.push(...data.list.filter(item => { return !item.Result }))
                this.mescroll.endSuccess(data.list.length);
                console.log(this.myList, '123', this.todoList);
            }).catch(() => {
                this.mescroll.endErr();
            })
        }
    },
}
</script>

css部分

<style lang="scss">
.net {
    .box-card {
        width: 380px;
        margin: 15px auto;
        border-radius: 5px;
    }

    .clearfix-header {
        display: flex;
        justify-content: center;
        justify-content: space-between;
    }

    .bodyname {
        margin-right: 60px;
    }

    .box-card-item {
        margin-bottom: 10px;

        .date {
            margin-top: 10px;
        }
    }

    // .bigbody {
    //     display: flex;
    //     justify-content: center;
    //     justify-content: space-between;
    //     padding: 10px;
    // }

    .parserbtn {
        margin: 0 38%;
    }
    // .shi{

    // }
    .xu{
        color: #909399;
    }
}
</style>

examination组件(开始/继续考试)

<template>
    <div class="net">
        <el-button type="info" class="navbtn" @click="$emit('isGoShow')" round><i
                class="icon-ym icon-ym-report-icon-preview-pagePre" style="margin-right: 10px;"></i>返回</el-button>
        <el-form :model="form" ref="uForm">
            <el-card class="box-card" v-for="(o, index) in paperItem" :key="index">
                <div slot="header" class="clearfix">
                    <span>{{ o.QuestionStem }}</span>({{ o.Point }}分)
                </div>
                <!-- 单选 -->
                <el-radio-group v-model="form.res[index]" v-if="o.QuestionType === '1'">
                    <div class="sitem" v-for="(i, ind) in o.Options" :key="ind"><el-radio :label="ind + 1">{{ i
                    }}</el-radio></div>
                </el-radio-group>
                <!-- 多选 -->
                <el-checkbox-group v-model="form.res[index]" v-if="o.QuestionType === '2'">
                    <div class="sitem" v-for="(i, ind) in o.Options" :key="ind"><el-checkbox :label="ind + 1">{{ i
                    }}</el-checkbox></div>
                </el-checkbox-group>
                <!-- <el-radio-group v-model="form.res[index]" v-if="o.QuestionType === '3'">
                    <div class="sitem"><el-radio :label="1">对</el-radio></div>
                    <div class="sitem"><el-radio :label="2">错</el-radio></div>
                </el-radio-group> -->
            </el-card>
        </el-form>
        <button @click="fn" style="margin: 10%;">提交</button>

        <!-- 弹出层 -->
        <el-dialog title="答题完成" :visible.sync="dialogVisible" width="80%" style="margin-top: 80px; border-radius: 5%;">
            <span>成绩为{{ grades }}!下次争取更进一步,自动跳转~</span>
            <span slot="footer" class="dialog-footer">
                <el-button type="primary" @click="isDialog">确 定</el-button>
            </span>
        </el-dialog>
    </div>
</template>
<script>
import { setPaperrItem } from "@/api/apply/paper"
export default {
    props: ['paperItem', 'form', 'newPaper', "config", 'id'],
    data() {
        return {
            forms: {},
            grades: 0,
            dialogVisible: false,
            datas: {
                data: {
                    tableField110: [],
                    Title: "",
                    F_CreatorUserId: "",
                    F_CreatorTime: "",
                    F_LastModifyTime: null,
                    Score: 0,
                    Result: "合格",
                    id: "",
                    flowId: "",
                    ExamineeAnswer:''
                },
                id: ""
            }
        };
    },
    created() {
        this.forms = this.form

    },
    methods: {
        fn() {
            // 非空校验
            console.log(this.forms.res,'99');
            let flag = this.forms.res.every(item => !!item)
            if (!flag) {
                uni.showToast({
                    title: '还有题未完成哦',
                    icon: 'error'
                });
                return
            } else {
                // 计算分数
                this.paperItem.forEach((item, ind) => {
                    if (item.QuestionType == 2) {
                    console.log(item);
                        if (item.Answer.sort().toString() == this.forms.res[ind].sort().toString()) this.grades += item.Point
                    } else {
                        if (item.Answer == this.forms.res[ind]) this.grades += item.Point
                    }
                })
                console.log(this.datas, this.newPaper, '11');
                this.datas.data.Title = this.newPaper.Title
                this.datas.data.F_CreatorUserId = this.newPaper.F_CreatorUserId
                this.datas.data.id = this.id
                this.datas.id = this.id
                this.datas.data.F_CreatorTime = this.newPaper.F_CreatorTime
                this.datas.data.Result = this.newPaper.Result
                this.datas.data.tableField110 = this.newPaper.tableField110
                this.datas.data.Score = this.grades
                // this.datas.data = JSON.stringify(this.datas.data)
                // console.log(this.config.flowId,this.datas.id,this.datas,'99');
                this.forms.res.forEach((item,ind) => {
                    if(item instanceof Array) {this.forms.res[ind] = item.toString()}
                    this.datas.data.tableField110.ExamineeAnswer = this.forms.res[ind]
                })
                this.datas.data = JSON.stringify(this.datas.data)
                setPaperrItem(this.config.flowId, this.datas.id, this.datas).then(res => {
                    console.log(res);
                })
                // this.$emit('setText')
                this.dialogVisible = true
                setTimeout(this.isDialog, 3000)
            }

        },
        isDialog() {
            this.dialogVisible = false
            this.$emit('isGoShow')
        }
    },
}
</script>

<style lang="scss">
.navbtn {
    margin-left: 15px;
    margin-top: 15px;
    font-size: 18px;
    padding-left: 10px;
}

.net {
    .box-card {
        width: 380px;
        margin: 15px auto;
        border-radius: 3%;
    }
}

.sitem {
    margin-bottom: 8px;
}
</style>

completedItem组件(试卷详情页面)

<template>
    <div class="net">
        <el-button type="info" class="navbtn" @click="$emit('isItem')" round><i
                class="icon-ym icon-ym-report-icon-preview-pagePre" style="margin-right: 10px;"></i>返回</el-button>
        <el-card class="box-card" :body-style="{ padding: '10px' }">
            <div>
                    <div slot="header" class="clearfix-header">
                        <span>{{ completedItem.Title }}</span> <span>测试结果:<span class="xu">{{ completedItem.Result }}</span> </span>
                    </div>
                    <div class="magin-b">
                        <div class="magin-t">得分:<span class="xu">{{ completedItem.Score }}</span></div>
                        <div class="bodyname magin-t">考试人:<span class="xu">{{ completedItem.F_CreatorUserId }}</span></div> 
                        <div class="date magin-t">交卷时间:<span class="xu">{{ completedItem.F_LastModifyTime }}</span></div>
                    </div>
                <el-card class="box-card-s" v-for="(o, index) in completedItem.tableField110" :key="index">
                    <div slot="header" class="clearfix">
                        <span>{{ o.QuestionStem }}</span>({{ o.Point }}分)
                    </div>
                    <!-- 单选 -->
                    <el-radio-group disabled v-model="formItem.res[index]" v-if="o.QuestionType === '1'">
                        <div class="sitem"  v-for="(i, ind) in o.Options" :key="ind"><el-radio
                                :label="ind + 1">{{ i
                                }}</el-radio></div>
                    </el-radio-group>
                    <!-- 多选 -->
                    <el-checkbox-group disabled v-model="formItem.res[index]" v-if="o.QuestionType === '2'">
                        <div class="sitem" v-for="(i, ind) in o.Options" :key="ind"><el-checkbox
                                :label="ind + 1">{{ i
                                }}</el-checkbox></div>
                    </el-checkbox-group>
                    <!-- 判断 -->
                    <!-- <el-radio-group v-if="o.QuestionType === '3'">
                        <div class="sitem"><el-radio :label="1">对</el-radio></div>
                        <div class="sitem"><el-radio :label="2">错</el-radio></div>
                    </el-radio-group> -->
                    <div class="tet">
                        正确答案:<span class="xu">{{ o.Answer }}</span>
                    </div>
                </el-card>
            </div>
        </el-card>

    </div>
</template>

<script>
export default {
    props: ['completedItem','formItem'],
    created() {
        console.log(this.completedItem,this.formItem, '90');
    }
}
</script>

<style lang="scss">
.tet {
    font-size: 16px;
    margin-top: 8px;
}
.magin-t{
    margin-top: 10px;
}
.magin-b{
    margin-bottom: 20px;
}
.box-card {
    width: 380px;
    margin: 15px auto;
    border-radius: 5px;
    padding: 10px;
    .box-card-s{
        margin-top: 7px;
    }
}
.clearfix-header{
    display: flex;
    justify-content: space-between;
}
.xu{
        color: #909399;
    }
</style>

这个页面难点我总结了一下

  1. 需要转化格式接受展示和上传提交都要转化格式(个人接口需求问题)

  1. element-ui多选框单选框的v-model值需要进行处理,组合多选框的值需要是个数组

  1. 提交表单答案对比其实只是第一感觉难,实际几行代码就解决了,单选题对比相等就相加分值,多选题数组排序方法后再转化为字符串对比是否相等

优点:因为我这个排版都是比较灵活的 后台想传多少选项就可以显示多少选项 且优势数据都在前端处理过了 可以省去后台很多功夫 他们只需要接收数据就行了。

因为我端口是用低代码生成的 需要处理数据 复用性没那么高 仅供阅读复制修改或者提供思路 如果想直接不用脑子复制粘贴的不太适合

然后需求是一步一步提出的,比如点击详情是做完后修改的,所以封装方面做的没那么优美哈。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
好的,我可以为您提供一个简单的示例代码,但需要注意的是,此示例代码仅用于参考目的,您需要根据自己的实际需求进行修改和优化。 首先,在Vue项目中安装Element UI库: ``` npm install element-ui -S ``` 然后,在您的Vue组件中引入Element UI的样式和组件: ```vue <template> <div class="login"> <el-form ref="loginForm" :model="form" label-width="80px"> <el-form-item label="用户名" prop="username"> <el-input v-model="form.username" auto-complete="off"></el-input> </el-form-item> <el-form-item label="密码" prop="password"> <el-input type="password" v-model="form.password" auto-complete="off"></el-input> </el-form-item> <el-form-item> <el-button type="primary" @click="login">登录</el-button> </el-form-item> </el-form> </div> </template> <script> import { ElForm, ElFormItem, ElInput, ElButton } from 'element-ui'; export default { name: 'Login', components: { ElForm, ElFormItem, ElInput, ElButton, }, data() { return { form: { username: '', password: '', }, }; }, methods: { login() { this.$refs.loginForm.validate(valid => { if (valid) { // TODO: 发送登录请求 console.log('登录成功'); } }); }, }, }; </script> <style> .login { margin: 50px auto; max-width: 500px; } </style> ``` 在上面的代码中,我们使用了Element UI的`el-form`、`el-form-item`、`el-input`和`el-button`组件来实现登录表单。当用户点击“登录”按钮时,我们调用`login`方法,该方法首先调用`validate`方法验证表单输入是否合法,如果合法则向服务器发送登录请求。 需要注意的是,在实际项目中,您还需要编写后端接口来处理登录请求,并且在登录成功后将用户的登录状态保存在本地或服务器端。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值