微信小程序(看文档写实例七)微信小程序课堂宝APP实现在线课堂测试
接着上篇博文已经完成签到功能,这篇来完成课堂测试功能。
一、需求描述
1、在后台选择题、主观题表中上传测试题
2、客户端获取题目信息
3、把题目信息格式化加载显示
4、客户端答题,主观题每题能上传一张答题图片
5、客户端答题结束提交到服务器
二、前台页面
提交大量数据当然用表单了,代码并不多。wxml代码如下:
<view class='section' hidden='{{selectedScrollItemsHiddenSign[1]}}'> <form bindsubmit="formSubmit"> <view class='section item-block' style='text-align: center;font-size=20px;'>{{onlineTestSeries}}</view> <view class='section item-block'>选择题</view> <view class='section item-block' wx:for="{{onlineTestChooseItems}}" wx:for-item="i" wx:key="*unique"> <view class='choose-item-title'>{{i.number_id}}、{{i.title}}</view> <radio-group class="radio-group" name="choose-radio-group{{i.number_id}}"> <label class="radio" wx:for="{{i.chooseItems}}" wx:key="*unique"> <radio value="{{item.name}}"/> {{item.value}} </label> </radio-group> </view> <view class='section item-block'>简答题</view> <view class='section item-block' wx:for="{{onlineTestSelfQuestionItems}}" wx:key="*unique"> <view class='choose-item-title'>{{item.number_id}}、{{item.title}}</view> <textarea class="answer-mainbody" name="answer-textarea{{item.number_id}}" placeholder="在这里写下您的答案..." type="textarea"/> <view class="answer-img" name="answer-img{{item.number_id}}" id="{{index}}" bindtap='chooseAnswerImage'></view> <text class='answer-img-text'>{{answerImgPaths[index].path}}</text> </view> <view class='section item-block'> <button formType="submit" class='btn-commit'>提交</button> </view> </form> </view> |
wcss代码如下:
/* 每个题目块样式 */ .item-block{ margin: 2%; background: rgb(232, 233, 232); color: royalblue; font-size: 15px; padding: 4%; border-radius: 3%; width: 96%; display: flex; flex-direction: column; } /* 单选题radio-group样式 */ .radio-group{ margin: 2%; display: flex; flex-direction: column; } /* 主观题答题区 */ .answer-mainbody{ height: 150px; margin: 2%; padding: 6px; font-family: monospace; white-space: pre-wrap; background: whitesmoke; border-radius: 3%; border: 1px solid rgb(214, 214, 214); } /* 主观题图片上传 */ .answer-img{ margin: 1%; background: url(http://i.pengxun.cn//content/images/imgpost2/01/post-big-pic-01.png) no-repeat 0 -286px; background-size: 100%; height: 26px; width: 26px; } .answer-img-text{ height: 25px; padding: 6px; /* 超出一行文字自动隐藏 */ overflow:hidden; /* 文字隐藏后添加省略号 */ text-overflow:ellipsis; /* 强制不换行 */ white-space:nowrap; } .btn-commit{ background: royalblue; color: whitesmoke; } |
三、后台代码
1、初始data
data: { // 选择题题目信息列表 onlineTestChooseItems:null, //课堂测试试题系列 onlineTestSeries:null, // 主观题题目信息列表 onlineTestSelfQuestionItems:null, // 模拟测试试题系列 simulateTestSeries: null, // 主观题答题图片路径列表 answerImgPaths:[], }, |
2、获取题目信息
/** * 获得课堂测试答题信息 * id为scroll-view menu中已经加载完成的index * testType为测试类型,可以是课堂测试、模拟测试或者其他,以服务器中的数据为参照 */ getPracticeItemsInfo:function(id,testType){ let query_choose = Bmob.Query('choose_item'); query_choose.order('number_id'); query_choose.equalTo("type", "==", testType); query_choose.find().then(res => { if(res.length>0){ if (testType=='课堂测试') that.setData({ onlineTestSeries:res[0].series}); else that.setData({ simulateTestSeries: res[0].series }); } var choose_items = new Array(); for (var i = 0; i < res.length; i++) { choose_items[i] = { objectId: res[i].objectId, number_id: res[i].number_id, title: res[i].title, chooseItems: [ { name: 'a', value: res[i].choose_item_a }, { name: 'b', value: res[i].choose_item_b }, { name: 'c', value: res[i].choose_item_c }, { name: 'd', value: res[i].choose_item_d } ] } } let query_subjective = Bmob.Query('subjective_item'); query_subjective.order('number_id'); query_choose.equalTo("type", "==", testType); query_subjective.find().then(res_subjective => { var subjective_items = new Array(); for (var i = 0; i < res_subjective.length; i++) { subjective_items[i] = { objectId: res_subjective[i].objectId, number_id: res_subjective[i].number_id, title: res_subjective[i].title }; } that.data.selectedScrollItemsLoadingComplete[id] = true; that.setData({ onlineTestChooseItems: choose_items, onlineTestSelfQuestionItems: subjective_items, selectedScrollItemsLoadingComplete: that.data.selectedScrollItemsLoadingComplete }); wx.hideToast(); }).catch(err => { wx.hideToast(); console.log(err.msg); wx.showToast({ title: '加载出错', duration: 2000 }); }); }).catch(err => { wx.hideToast(); console.log(err); wx.showToast({ title: '加载出错', duration: 2000 }); }); }, |
3、上传主观题图片
先上传主观题图片,然后把上传好的url记录下来,最后保存到对应的主观题目即可。查看文档发现上传图片要用wx.api中的wx.chooseImage(Object object),object的参数如下表:
属性 | 类型 | 默认值 | 是否必填 | 说明 |
---|---|---|---|---|
count | number | 9 | 否 | 最多可以选择的图片张数 |
sizeType | Array.<string> | ['original', 'compressed'] | 否 | 所选的图片的尺寸 |
sourceType | Array.<string> | ['album', 'camera'] | 否 | 选择图片的来源 |
success | function | 否 | 接口调用成功的回调函数 | |
fail | function | 否 | 接口调用失败的回调函数 | |
complete | function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
于是得到如下上传代码:
// 主观题选择答题拍照或者图片 chooseAnswerImage: function(e) { wx.chooseImage({ count: 1, // 默认9 sizeType: ['original'], // 指定是原图 sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有 success: function(res) { // 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片 // 如果该题已经上传答题图片则先删除原先的图片 var currentAnswerImgPathsItem = that.data.answerImgPaths[e.currentTarget.id]; if (currentAnswerImgPathsItem != null) { // 传入string是单个文件删除,传入array是批量删除 var del = Bmob.File(); del.destroy([currentAnswerImgPathsItem.file.url]).then(res1 => { that.uploadAnswerImg(e.currentTarget.id, res.tempFilePaths[0]); }).catch(err => { console.log(err); wx.showToast({ title: '图片上传失败', duration: 2000 }) }) } else { that.uploadAnswerImg(e.currentTarget.id, res.tempFilePaths[0]); } } }); }, uploadAnswerImg: function(pathId, pathImg) { // 上传选中的图片 var file = Bmob.File('subjectImg.jpg', pathImg); wx.showToast({ title: '正在上传', icon: 'loading', duration: 10000 }); file.save().then(res => { wx.hideToast(); wx.showToast({ title: '图片上传成功', duration: 2000 }) that.data.answerImgPaths[pathId] = { path: pathImg, file: res[0] }; that.setData({ answerImgPaths: that.data.answerImgPaths }); }).catch(err => { console.log(err); wx.showToast({ title: '图片上传失败', duration: 2000 }) }); }, |
4、提交答题数据
提交答案分选择题和主观题,主观题还有对应的图片,由于bmob中pointer类型不能直接新增,因此在新增一条含有pointer字段的数据时,要先增其他的信息成功后在回调函数中再把对应的pointer类型数据插入。下面是上传一个题目的代码:
/** * 上传单个题信息 * value是题目信息 * itemType是题目类型 */ uploadAItemAnswersInfo: function(value, itemType) { var query = Bmob.Query('choose_item_submit'); query.set("answer", value.answer); if (value.file != null) query.set("subjectiveImg", value.file); // 先保存answer和上传成功的图片信息 query.save().then(res => { query.get(res.objectId).then(res1 => { // 保存关联对象 // 设置用户关联对象 var userIdPointer = Bmob.Pointer('_User'); var pointerUserId = userIdPointer.set(value.userId); res1.set('userId', pointerUserId); if (itemType == 'choose') { // 设置选择题关联对象 var chooseItemIdPointer = Bmob.Pointer('choose_item'); //关联字段 var pointerIdChooseItemId = chooseItemIdPointer.set(value.chooseItemId); res1.set('chooseItemId', pointerIdChooseItemId); // 设置后保存 res1.save(); } else { // 设置主观题关联对象 var subjectItemIdPointer = Bmob.Pointer('subjective_item'); //关联字段 var pointerIdSubjectItemId = subjectItemIdPointer.set(value.subjectItemId); res1.set('subjectiveItemId', pointerIdSubjectItemId); res1.save(); } return true; }); }).catch(err => { wx.showToast({ title: '上传失败', duration: 2000 }); return false; }); }, |
接下来是只要把表单中的所有答题信息遍历,按类型上传即可,不过再上传结果判定时要确保每个题目都已经上传,有一个题目上传不成功就提示没有提交成功。下面是上传所有答题数据的代码:
/** * 上传所有答案信息 * value是表单提交上来的信息 */ uploadAnswersInfo: function(value) { // 显示加载loading wx.showToast({ title: '提交中...', icon: 'loading', duration: 1000 }); // 上传题目结果列表 var allUploadSuccess = []; // 选择题索引 var chooseItemIndex = 0; // 主观题索引 var subjectiveItemIndex = 0; // 遍历submit提交的数据 for (var keyname in value) if (value[keyname] != "") { //console.log(value.keyname); // 判断是否是单选题 var data = {}; if (keyname.indexOf('choose-radio-group') != -1) { data = { userId: app.globalData.currentUser.objectId, chooseItemId: that.data.onlineTestChooseItems[chooseItemIndex].objectId, file: null, answer: value[keyname] } allUploadSuccess[chooseItemIndex + subjectiveItemIndex] = that.uploadAItemAnswersInfo(data, 'choose'); chooseItemIndex++; } else { var fileName = null; if (that.data.answerImgPaths[subjectiveItemIndex] != null) fileName = that.data.answerImgPaths[subjectiveItemIndex].file; data = { userId: app.globalData.currentUser.objectId, subjectItemId: that.data.onlineTestSelfQuestionItems[subjectiveItemIndex].objectId, file: fileName, answer: value[keyname] } allUploadSuccess[chooseItemIndex + subjectiveItemIndex] = that.uploadAItemAnswersInfo(data, 'subjective'); subjectiveItemIndex++; } } // 定时监听所有返回结果 var checkResult = setInterval(function() { if (allUploadSuccess.length == that.data.onlineTestChooseItems.length + that.data.onlineTestSelfQuestionItems.length) { var allUploadSuccessFlag = true; for (var i = 0; i < allUploadSuccess.length; i++) { if (allUploadSuccess[i] == false) { allUploadSuccessFlag = false; if (i > that.data.onlineTestChooseItems.length) wx.showToast({ title: '第' + (i + 1) + '选择题上传失败', duration: 1000 }); else { wx.showToast({ title: '第' + (i + 1 - that.data.onlineTestChooseItems.length) + '主观题上传失败', duration: 1000 }); } } } // 清除定时器 clearInterval(checkResult); wx.hideToast(); // 所有题目都成功提交 if (allUploadSuccessFlag) { // 上传提交记录 var query = Bmob.Query('submit_record'); query.set("type", '课堂测试'); query.set('series', that.data.onlineTestSeries); query.save().then(res => { query.get(res.objectId).then(res1 => { var pointer = Bmob.Pointer('_User'); var poiID = pointer.set(app.globalData.currentUser.objectId); res1.set('userId', poiID); res1.save(); // 显示加载logo wx.showToast({ title: '提交成功', duration: 3000 }); }).catch(err => {}); }).catch(err => {}); } } else { wx.showToast({ title: '提交中...', icon: 'loading', duration: 1000 }); } }, 1000); }, |
四、效果
1、服务器题目信息
选择题信息
主观题信息
2、获取题目信息加载
3、提交结果
然后课堂测试和模拟测试功能一样,就是换个数据,因为课堂提问要实时推送,而bmob实时推送是收费的,这在后面做最后的完成,下节先实现练习模块的前台。
微信小程序(看文档写实例七)微信小程序课堂宝APP实现在线课堂测试相关推荐
- 微信小程序(看文档写实例三)微信小程序课堂宝APP实现整体界面框架及首页布局
一.首页布局简单思路 回顾上一篇博文,首页的内容主要有轮播图,横向滑动菜单以及菜单对应的view,横向滑动菜单有签到.课堂测试.模拟测试.课堂提问.答问记录五个选项,当点击选项时更新显示view.由于 ...
- 微信小程序(看文档写实例二)微信小程序课堂宝APP
全程记录APP的开发过程,项目完结公上传Github. 一.需求 由于老板让做一个课堂信息化APP,想想在移动端开发,小程序不分Android和IOS,所以就选择了微信小程序,软件的需求不多,但整体内 ...
- 微信小程序(看文档写实例十)微信小程序课堂宝APP实现我的模块相关界面及逻辑
继上篇博文,这篇完成最后一个模块,即我的模块. 一.页面效果 这个模块是和用户类型相关的,因此老师账号和学生账号能看的功能不一样,老师端效果如下: 点击头像到达个人信息如下: 点击后可以做相应的修改. ...
- 微信小程序(看文档写实例十一)微信小程序课堂宝APP完结总结及github地址
一.总结 国庆假期偷懒了几天,从接到任务到分析到实现总共花了20天左右,终于完成了,点名功能由于要实时监听需要收费,所以没有给出代码,需要完成的可以自己动手实现.用一张导图来结束: 二.源码地址 所有 ...
- 微信小程序(看文档写实例六)微信小程序课堂宝APP实现签到逻辑
继上篇博文,这篇写下签到实现的逻辑. 一.实现逻辑 发起签到 1.先上传当前自己的定位经纬度 2.学生查询老师的最后一次签到记录,如果发现签到记录signComplete为false说明有新的签到 3 ...
- 微信小程序(看文档写实例八)微信小程序课堂宝APP实现练习模块前台
接上篇博文,这篇主要描述练习模块的前台显示,其中包括test页面,答题detail页面以及提交答题后答卷answer页面. 一.练习模块test页面 练习页面主要展示的是当前用户的头像,昵称以及学校信 ...
- 微信小程序(看文档写实例四)微信小程序课堂宝APP实现签到子页面布局及课程视频播放页面
一.签到子页面布局 子页面主要是一个签到按钮,然后下方是签到记录列表. 1.签到按钮 布局代码: <button class='sign-button' bindtap='sign'>签到 ...
- 微信小程序(看文档写实例五)微信小程序课堂宝APP实现获取签到列表
根据上篇博文,这篇主要实现获取签到列表逻辑. 获得签到列表主要有以下步骤: (1)查询老师的ID (2)查询老师的签到记录 (3)如果当前用户是老师,直接显示所有记录,因为签到记录都是老师发起的,肯定 ...
- 微信小程序(看文档写实例九)微信小程序课堂宝APP实现练习模块逻辑代码
接上篇博文,这篇主要描述练习模块的代码逻辑,其中包括test页面,答题detail页面以及提交答题后答卷answer页面. 一.test页面 test页面其实就是从服务器获得章节练习题的内容,然后统计 ...
- python使用微信设置-微信 python 接口 -- itchat 文档
itchat 一. 安装 $ pip install itchat 特殊的字典使用方式 通过打印 itchat 的用户以及注册消息的参数, 可以发现这些值都是字典. 但实际上 itchat 精心构造了 ...
最新文章
- Ubuntu 10.10 安装 libx11-dev
- cross-env使用
- VM虚拟机下安装CentOS_6.5_x64
- Centos6.4_X64飞信安装
- 从严治码-别人在项目中下毒,我该怎么治?
- 什么?面试官问我Java内存模型!这不得给我加薪?
- 使用Server 2008新GPO做驱动器映射
- 9203-1117-实现数据库的查询功能
- 浅谈服务器使用RAID5磁盘阵列的问题
- JavaScript 框架之战结束:React 是最终赢家?
- 【读书笔记】 多线程程序常见bug
- [zhuan]asp.net程序性能优化的七个方面 (c#(或vb.net)程序改进)
- 报价管理:用VBA开发灵活的报价系统
- 自动化办公-Python处理Excel生成试卷
- c语言中动态内存分配的作用,C语言中动态内存的分配(malloc,realloc)
- 湖南大学应用经济学考研考情与难度、参考书及上岸前辈备考经验
- 菜鸟学算法--二分查找
- RFQ 、IFB、RFP 、RFI的区别是什么
- Java内存中神奇的64MB
- 华为mate50参数配置 华为mate50是5g吗
热门文章
- 基于java的智能手表_基于安卓Android智能手环(计步器)APP设计(含录像)
- 非线性系统离散线性化方法(一)
- 【1800题】一、函数、极限、连续
- CUDA编程技术汇总
- PHP通用网站后台管理系统
- xp计算机考试资源管理,职称计算机WindowsXP必备考点:资源管理器
- “开闭原则”实现图书售卖简单实现
- 伍德里奇计量经济学第四章计算机答案,计量经济学中文答案 伍德里奇
- 用外挂只为“吃鸡”成功?为什么不试试正当手段!
- 使用gooflow和easyui做的一个工作流程配置图