调查表模板
这次我和大家分享一下如何用小程序做一个问卷调查小程序,可以是行业问卷,或者是测试题的。该问卷调查主要介绍题目多且题型多,题目数在15道以上,题型包含单选,非必做、必做题,填空题。当然可以从这些衍生更多的出来。
首先理清思路:第一页我们做欢迎语和简介,在答题入口上做跳转题目页和授权按钮功能,然后开始做题,选择题放前,填空题放后,每页2道题,任何一道为空都会提示“请做完本页所有题”,当遇到选做题,则选做题可不做,但剩下那道题则必做才可以继续下一页,当遇到填空题和选择题交叉,则判断填空题的输入域是否为空,选择题是否选做。提交按钮将所有数据以字符串发送服务器。
###第一步、做欢迎页和介绍页。
先上效果图:
在开始答题的按钮上,我们做跳转和授权两个函数。
授权示意图:
如果对授权不太了解的可以参考我的置顶博文,有介绍小程序的getPhonenumber组件功能的内容。
代码我也给大家放上
页面内容:
<button class='index_btn' style='line-height:normal;' wx:if="{{btnShow}}" bindtap='' open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber">开始答题</button>
JS内容,将跳转放在授权里面,授权成功则跳转做题,授权取消,停留当前页面:
//通过绑定手机号登录
getPhoneNumber: function (e) {
var ivObj = e.detail.iv
var telObj = e.detail.encryptedData
var codeObj = "";
var that = this;
//------执行Login
wx.login({
success: res => {
console.log('code转换', res.code); //用code传给服务器调换session_key
wx.request({
url: 'https://x.xxxxxxx.com/xiaochengxu/demo.php', //接口地址
data: {
APPid: "小程序appid",
secret: "小程序密钥",
code: res.code,
encryptedData: telObj,
iv: ivObj
},
header: {
'content-type': 'application/json' // 默认值
},
success: function (res) {
phoneObj = res.data.phoneNumber;
console.log("手机号=", phoneObj)
wx.setStorage({ //存储数据并准备发送给下一页使用
key: "phoneObj",
data: res.data.phoneNumber,
})
}
})
//-----------------是否授权决定是否可以做题
if (e.detail.errMsg == 'getPhoneNumber:fail user deny') { //用户点击拒绝判断
wx.navigateTo({
url: '../index/index',
})
} else { //授权通过执行跳转
wx.navigateTo({
url: '../test/test',
})
}
}
});
//---------登录有效期检查
wx.checkSession({
success: function () {
//session_key 未过期,并且在本生命周期一直有效
},
fail: function () {
// session_key 已经失效,需要重新执行登录流程
wx.login() //重新登录
}
});
},
###第二步、答题页面
首先我先放上页面题目展示效果:
这里是两个题目为一页,选做题和必选题以及填空题也是这样排列。
页面内的布局写法:
<form bindsubmit="formSubmit" bindreset="formReset">
<!-- 两道题联动 -->
<view class='page {{page ==1?"on":""}}'>
<import src="radio_my.wxml"/>
<template is="radio" data="{{my: my,title:myHospitalQuestionnaireData[0],ind:1}}"/>
<import src="radio_my.wxml"/>
<template is="radio" data="{{my: my,title:myHospitalQuestionnaireData[1],ind:2}}"/>
</view>
<!-- 两道题联动 -->
<view class='page {{page ==2?"on":""}}'>
<import src="radio_my.wxml"/>
<template is="radio" data="{{my: my,title:myHospitalQuestionnaireData[2],ind:3}}"/>
<template is="radio" data="{{my: my,title:myHospitalQuestionnaireData[3],ind:4}}"/>
</view>
<view class='page {{page ==3?"on":""}}'>
<import src="radio_my.wxml"/>
<template is="radio" data="{{my: my,title:myHospitalQuestionnaireData[4],ind:5}}"/>
<template is="radio" data="{{my: my,title:myHospitalQuestionnaireData[5],ind:6}}"/>
</view>
<view class='page {{page ==4?"on":""}}'>
<import src="radio_my.wxml"/>
<template is="radio" data="{{my: my,title:myHospitalQuestionnaireData[6],ind:7}}"/>
<template is="radio" data="{{my: my,title:myHospitalQuestionnaireData[7],ind:8}}"/>
</view>
<view class='page {{page ==5?"on":""}}'>
<import src="radio_my.wxml"/>
<template is="radio" data="{{my: my,title:myHospitalQuestionnaireData[8],ind:9}}"/>
<template is="radio" data="{{my: my,title:myHospitalQuestionnaireData[9],ind:10}}"/>
</view>
<view class='page {{page ==6?"on":""}}'>
<import src="radio_my.wxml"/>
<template is="radio" data="{{my: my,title:myHospitalQuestionnaireData[10],ind:11}}"/>
<template is="radio" data="{{my: my,title:myHospitalQuestionnaireData[11],ind:12}}"/>
</view>
<view class='page {{page ==7?"on":""}}'>
<import src="radio_my.wxml"/>
<template is="radio" data="{{my: my,title:myHospitalQuestionnaireData[12],ind:13}}"/>
<import src="textarea.wxml"/>
<template is="textarea" data="{{data:myHospitalQuestionnaireData[13],ind:14,pla:'请填写您最满意的医生、护士'}}"/>
</view>
<!-- 最终提交 -->
<view class='page {{page ==8?"on":""}}'>
<import src="textarea.wxml"/>
<template is="textarea" data="{{data:myHospitalQuestionnaireData[14],ind:15,pla:'请填写您的具体建议...'}}" value="{{userInfo.nickName}}"/>
<!-- <import src="login.wxml"/>
<template is="login" data="{{data:myHospitalQuestionnaireData[15],ind:16}}" /> -->
</view>
<!-- 最终提交 -->
<!-- 最后一页 -->
<view class="footer-btn">
<button class="btn-tj {{page_prev?'on':''}}" bindtap="prevPage" >上一页</button>
<button formType="submit" class="btn-tj {{page_next?'on':''}}" bindtap="nextPage" wx:if="{{page!=page_num}}">下一页</button>
<button class="btn-tj {{page_next?'on':''}}" wx:if="{{page==page_num}}" formType="submit" style='background:#19be6b;'>提交</button>
<!-- -->
</view>
<view class='page_num'>第{{page}}页 共{{page_num}}页</view>
<import src="modal.wxml"/>
<template is="modal" data="{{msg:modaltext,show:modalShow}}"/>
</form>
以form表单来提交数据很简单方便的。对于不同体型,我们做不同的模板调用,这样格式统一样式统一,选择题用一个,填空题用一个。
例如:
<template name="radio">
<view class="container">
<view class="ask-wrap">
<view class="ask-title">{{ind}}、{{title.title}}</view>
<view class="ask-area">
<radio-group class="radio-group" name="group_{{title.id}}" bindchange='radioChange' id="{{title.id}}">
<label class="radio" bindchange="radioChange" wx:for="{{my}}" wx:key="" wx:for-index="index" data-index="{{index}}" >
<radio value="{{item.value}}" checked="{{item.checked}}"/>{{item.con}}
</label>
</radio-group>
</view>
</view>
</view>
</template>
这是选择题的。题目序号,题目内容和选项都布局好了,在题目页就更好罗列出来。
那么答题页面的JS如何写的呢?
附加代码:
var common = require('../../utils/common.js');
//获取应用实例
var app = getApp();
//存储全局
var phoneObj = '';
Page({
data: {
show: true,
page: 1,
one: false,
two: false,
page_num: 0,
phoneObj: '',
page_prev: false,
page_next: true,
result: {},
doctor: [],
modaltext: "出错了",
modalShow: false,
doctorValue: "",
addMsgs: "",
nextShow: "false",
my: [{
value: "1",
con: "满意"
}, {
value: "2",
con: "基本满意"
}, {
value: "3",
con: "不满意"
}],
zd: [{
value: "1",
con: "知道"
}, {
value: "2",
con: "不知道"
}],
zd1: [{
value: "1",
con: "满意"
}, {
value: "2",
con: "基本满意"
}, {
value: "3",
con: "不满意"
}],
myHospitalQuestionnaireData: []
},
onShow() { //清空一部分数据 文本不知道怎么清除
this.setData({
page: 1,
page_prev: false,
zd: [{
value: "1",
con: "知道"
}, {
value: "2",
con: "不知道"
}],
my: [{
value: "1",
con: "满意"
}, {
value: "2",
con: "基本满意"
}, {
value: "3",
con: "不满意"
}],
zd1: [{
value: "1",
con: "满意"
}, {
value: "2",
con: "基本满意"
}, {
value: "3",
con: "不满意"
}]
})
},
onLoad() {
var that = this;
wx.request({
url: 'https://xx.xxxxx.com/js/HospitalQuestionnaire.js', //将测试题封装在JS中调用里面的题目
header: {
'content-type': 'json'
},
success: function(res) {
// console.log(res.data)
that.setData({
myHospitalQuestionnaireData: res.data //页面题目内容展示的data数据名
});
that.setData({
page_num: Math.ceil(that.data.myHospitalQuestionnaireData.length / 2) //每页题目数
});
}
})
},
radioChange(e) {
var arr = this.data.myHospitalQuestionnaireData;
if (e.currentTarget.id == arr[0].id) {
if (e.detail.value == "1") {
this.setData({
one: true
});
} else {
this.setData({
one: false
});
}
}
if (e.currentTarget.id == arr[2].id) {
if (e.detail.value == "1") {
this.setData({
two: true
});
} else {
this.setData({
two: false
});
}
}
var oldval = this.data.result;
oldval[e.currentTarget.id] = e.detail.value;
this.setData({
result: oldval
});
},
bindKeyInput(e) {
this.setData({
doctorValue: e.detail.value
});
},
//--------
addDoctor() {
if (this.data.doctorValue == "") {
this.modalShow({
msg: "您还没有填写任何内容"
});
return;
}
var oldarr = this.data.doctor;
oldarr.push(this.data.doctorValue);
this.setData({
doctor: oldarr,
doctorValue: ""
});
},
//------------
//意见建议
textBlur: function(e) {
if (e.detail && e.detail.value.length > 0) {
if (e.detail.value.length < 1 || e.detail.value.length > 500) {
//app.func.showtoast('内容为12-500个字符','loading',1200);
} else {
this.setData({
addMsgs: e.detail.value
});
}
} else {
this.setData({
addMsgs: ''
});
evaData.addMsgs = '';
app.func.showToast('请输入投诉内容', 'loading', 1200);
}
},
prevPage() {
if (this.data.page > 1) {
this.data.page--;
this.setData({
page: this.data.page--
});
if (this.data.page == "1") {
this.setData({
page_prev: false
});
}
} else {
this.setData({
page_prev: false
});
this.modalShow({
msg: "已经没有上一页了"
});
return;
}
},
chooseDel(e) {
let id = e.currentTarget.id,
oldarr = this.data.doctor;
oldarr.splice(id, 1);
this.setData({
doctor: oldarr
});
},
//-----------
//下一页 / 表单提交
formSubmit: function(e) {
// console.log('提交数据', e.detail.value);
var that = this;
var telPhone = wx.getStorageSync('phoneObj'); //读取登录手机号信息并不断刷新是否丢失
console.log('---------', telPhone)
//----------
var page = this.data.page, //做题页数
arr = this.data.myHospitalQuestionnaireData, //题目总数
boo = true;
if (this.data.page != Math.ceil(arr.length / 2)) {
for (var i = 0; i < arr.length; i++) {
var index = arr[i].id; //数据编号
if (index != "47" && index != "48") { //判断选做题为空
if (i < page * 2) {
if (e.detail.value["group_" + index] == '') {
boo = false;
}
if (e.detail.value["group_" + index] == '') {
console.log(index)
}
}
}
}
} else {
let that = this,
obj = e.detail.value,
key = Object.keys(obj),
len = this.data.myHospitalQuestionnaireData.length;
common.extend(arr, {
len: len.toString()
});
let str = "",
ind = 0;
for (var i = 0; i < key.length; i++) {
str += "&" + key[i] + "=" + e.detail.value[key[i]];
ind++;
}
console.log(obj)
console.log(telPhone)
if (telPhone != "" || telPhone != undefined || telPhone != null) { //再次确认手机号是否携带值
wx.showModal({
title: '提示',
content: '确认要提交吗',
success: function(res) {
if (res.confirm) {
req();
} else if (res.cancel) {
console.log('用户点击取消')
}
}
});
} else {
this.modalShow({
msg: "请稍后重试"
});
}
function req() {
if (telPhone != "" || telPhone != undefined || telPhone != null) { //最终确认手机号有值
wx.request({
url: 'https://x.xxxxx.com/manage/wenjuan/questionnaire.ashx?project=zz&len=' + len.toString() + str + '&group_56=' + telPhone, //提交的数据的地址以及格式包括授权过来的手机号
method: "POST",
data: obj,
header: {
'content-type': 'application/json'
},
success: function(res) { //查询提交数据内容
console.log(res.data)
// console.log("111", obj)
// console.log('&group_56=', telPhone)
var message = res.data;
if (message == "" || message == undefined || message == null) {
wx.showModal({
title: '提示',
content: '操作频繁',
success: function (res) {
if (res.confirm) {
wx.redirectTo({
url: '../index/index',
});
} else if (res.cancel) {
console.log('用户点击取消')
}
}
});
} else {
that.modalShow({
msg: res.data
});
settimeout(function() {
wx.navigateTo({
url: "../result/result"
})
}, 1000);
};
}
})
} else {
that.modalShow({
msg: "提交失败"
});
wx.navigateTo({
url: '../test/test',
})
}
}
}
//----条件判断
if (boo) {
if (this.data.page < Math.ceil(arr.length / 2)) {
this.data.page++;
this.setData({
page: this.data.page++,
page_prev: true
});
} else {
return;
}
} else {
this.modalShow({
msg: "请答完本页内所有题目"
});
}
},
//控制弹出层开启
modalShow(para) {
let deault = {
msg: "出错了",
time: 1500
}
common.extend(deault, para);
this.setData({
modalShow: true,
modaltext: deault.msg
});
let that = this;
setTimeout(function() {
that.setData({
modalShow: false
});
}, deault.time);
},
//弹出层关闭
modalHide() {
this.setData({
modalShow: false
});
},
formReset() {
console.log('form发生了reset事件')
}
})
//-----------
var myHospitalQuestionnaireArrMY = [{
value: "1",
con: "满意",
checked: 'true'
}, {
value: "2",
con: "基本满意"
}, {
"value": "3",
"con": "不满意"
}];
var myHospitalQuestionnaireArrZD = [{
value: "1",
con: "知道",
checked: 'true'
}, {
value: "2",
con: "不知道"
}];
我是把所有的判断都写在这测试题JS中了,小伙伴可以封装写在util.js中。
页面展示一下不同情况的效果吧:
例如:全做的可以跳转
例如:没做的提示请做完并禁止跳转
例如:选做题都不做则不给跳转
不做选做,但是做了剩下的则跳转
反制如果做了选做,不做必做的则也不跳转,判断用的是同一个判断:
//----条件判断
if (boo) {
if (this.data.page < Math.ceil(arr.length / 2)) {
this.data.page++;
this.setData({
page: this.data.page++,
page_prev: true
});
} else {
return;
}
} else {
this.modalShow({
msg: "请答完本页内所有题目"
});
}
还有:如果填空题不做,则也不跳转
这样就完成了所有的判断。
最后的提交按钮写法:
<!-- 最后一页 -->
<view class="footer-btn">
<button class="btn-tj {{page_prev?'on':''}}" bindtap="prevPage" >上一页</button>
<button formType="submit" class="btn-tj {{page_next?'on':''}}" bindtap="nextPage" wx:if="{{page!=page_num}}">下一页</button>
<button class="btn-tj {{page_next?'on':''}}" wx:if="{{page==page_num}}" formType="submit" style='background:#19be6b;'>提交</button>
<!-- -->
</view>
为什么这样写呢?
因为在做题和提交上我们用的一直是同一个按钮,也就是form的提交按钮,对其样式做三目运算来判断该显示是下一页还是显示提交。也就是罗列题目是,题目数全部跳完则显示提交按钮。
最后提醒下:
防止数据丢失,或者授权信息丢失,可以在每次跳转下一页的时候都打印一次。确保最后全部数据可以传输。
本文只提供思路;商业机密无法提供完整代码,可以在评论区和我探讨这些问题。
相关阅读
废品回收业全球化已经是世界经济的一个永恒特征,与智能手机制造业全球化并无区别,持久性也毫不缩水。“回收旧冰箱,旧彩电,旧洗衣机…
Design Systems Ops:设计师如何跟开发打好关系?
伟大的产品离不开开发和设计的良好沟通。无论你是谁,归根结底,我们都是在创造软件产品。有了设计系统之后,沟通将变得更加简单。但是
掉进坑不打紧,多总结和感悟是必须的,从理论到实践中去是一定要的!如果只停留在机械思维,而没有自己的方法论也是不行的。这条路上,我们
平均年收入:约36万人民币最大年收入:约96万人民币求人件数:2200件(按汇率为0.06计算)Go:(又称Golang)是Google开发的一种静态强类型、编译
一 谷歌地球概述 谷歌地球(Google Earth,GE)是一款谷歌公司开发的虚拟地球仪软件,它把卫星照片、航空照相和GIS布置在一个地球的三维