微信小程序(看文档写实例七)微信小程序课堂宝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的参数如下表:

属性类型默认值是否必填说明
countnumber9最多可以选择的图片张数
sizeTypeArray.<string>['original', 'compressed']所选的图片的尺寸
sourceTypeArray.<string>['album', 'camera']选择图片的来源
successfunction 接口调用成功的回调函数
failfunction 接口调用失败的回调函数
completefunction 接口调用结束的回调函数(调用成功、失败都会执行)

于是得到如下上传代码:

// 主观题选择答题拍照或者图片

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实时推送是收费的,这在后面做最后的完成,下节先实现练习模块的前台。

  • 10
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
### 回答1: 微信小程序开发实例zip是指将多个小程序实例文件打包成一个zip压缩文件。这个压缩文件可以方便地在微信小程序开发工具中导入和使用。 开发者在开发微信小程序时,通常会创建多个小程序实例文件,比如页面、组件、工具类等等。为了方便管理和分享这些实例文件,可以将它们打包成一个zip文件。 具体操作步骤如下: 1. 将要打包的小程序实例文件放入一个文件夹中。 2. 右键点击这个文件夹,选择“压缩”或“打包”菜单。 3. 选择压缩格式为zip,并设置压缩文件的保存路径及名称。 4. 等待压缩完成,得到一个zip文件。 通过这个zip文件,可以在微信小程序开发工具中进行导入和使用。具体操作步骤如下: 1. 打开微信小程序开发工具,点击“项目”-“导入项目”菜单。 2. 在导入项目弹窗中,选择zip格式,并点击“下一步”按钮。 3. 设置项目导入的路径和名称,并点击“确定”按钮。 4. 等待导入完成,即可在微信小程序开发工具中查看和使用这些小程序实例文件。 需要注意的是,导入后的实例文件可能需要进行相应的配置和调整才能正常运行。例如,需要在app.json文件中添加对应的页面路径、组件路径等配置。 总结:微信小程序开发实例zip是一种方便的文件管理和分享方式,可将多个小程序实例文件打包成一个zip压缩文件。开发者可以通过微信小程序开发工具进行导入和使用,但需注意进行相应的配置和调整。 ### 回答2: 微信小程序开发实例zip是一种压缩文件格式,通常用于将多个文件或文件夹压缩成一个单独的文件,方便传输和存储。 在微信小程序开发中,如果我们需要将多个文件打包成一个文件,可以使用zip来实现。具体步骤如下: 1. 准备需要打包的文件或文件夹。可以是多个文件,也可以是一个文件夹中的多个文件。 2. 将需要打包的文件或文件夹放在同一个目录下。 3. 使用相关的压缩软件,如WinRAR或7-Zip等,对这些文件或文件夹进行压缩,生成一个zip文件。 4. 在微信小程序开发中,通过选择文件的方式将生成的zip文件上传至小程序的资源目录中。 5. 在小程序代码中,利用相关的解压函数对zip文件进行解压,将其中的文件恢复到原来的状态。例如,可以使用JSZip库进行解压操作。 6. 解压完成后,就可以通过小程序的API对解压后的文件进行相关操作。比如,读取文件内容、展示图片等。 需要注意的是,在解压之前,我们需要确认用户已经授权允许小程序进行文件操作的权限,以确保能够正常进行解压操作。 以上就是一个关于微信小程序开发实例zip的简要说明。通过将多个文件打包成一个zip文件,可以方便地进行传输和存储,并通过解压操作实现对文件的恢复和使用。 ### 回答3: 微信小程序开发实例zip是一种常用的文件压缩格式,通过压缩多个文件或文件夹,可以减小文件的大小,方便传输和存储。 在微信小程序开发中,如果需要将多个文件或文件夹打包成zip格式,可以借助第三方库JSZip实现。JSZip是一个轻量级的JavaScript库,可以用来创建和读取zip文件。 下面是一个简单的微信小程序开发实例,展示如何使用JSZip库进行文件打包压缩: 1. 首先,在小程序项目中引入JSZip库。可以使用npm安装JSZip,并使用wxss引入: ``` npm install jszip ``` 2. 在小程序的逻辑层(js文件)中,通过require引入JSZip库: ``` const JSZip = require('./path/to/jszip.min.js'); ``` 3. 创建一个JSZip实例并向其添加需要压缩的文件或文件夹: ``` const zip = new JSZip(); zip.file('file1.txt', 'Hello World!'); zip.file('file2.txt', 'This is a test.'); zip.folder('folder1').file('file3.txt', 'Welcome to folder1.'); ``` 在上面的例子中,我们创建了一个zip实例,并添加了3个文件,file1.txt、file2.txt和folder1/file3.txt。 4. 调用JSZip的generateAsync方法生成压缩文件: ``` zip.generateAsync({ type: "blob" }) .then(function(content) { wx.saveFile({ tempFilePath: content.tempFilePath, success: function(res) { console.log(res.savedFilePath); } }); }); ``` 在上面的例子中,我们调用了generateAsync方法,生成一个Blob对象,然后通过wx.saveFile保存该文件,并得到其保存路径。 通过以上步骤,我们可以在微信小程序中使用JSZip库进行文件打包压缩,并将压缩文件保存到本地。 需要注意的是,由于微信小程序的运行环境限制,JSZip的部分高级功能可能无法在小程序中完全实现,开发者需要根据实际需求选择合适的压缩库或者适应某些功能的缺失。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值