微信小程序(看文档写实例七)微信小程序课堂宝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实现在线课堂测试的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 硅谷课堂笔记(上)
- 下一篇: 很详细的解决Tomcat乱码问题