uniapp + node.js 开发问卷调查小程序

这篇具有很好参考价值的文章主要介绍了uniapp + node.js 开发问卷调查小程序。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前后端效果图
uniapp + node.js 开发问卷调查小程序,uni-app,nodejs,uni-app,node.js,小程序
后端:nodejs 12.8 ; mongoDB 4.0
前端:uniapp
开发工具:HBuilderX 3.99文章来源地址https://www.toymoban.com/news/detail-799413.html

  • 前端首页代码 index.vue
<!-- 源码下载地址  https://pan.baidu.com/s/1AVB71AjEX06wpc4wbcV_tQ?pwd=l9zp -->

<template>
	<view class="container">
		<view class="content">
			<view class="question" v-for="(item,index) in qusetionList" :key='index'>
				<view class="question_header">
					<view class="header_title">
						{{item.subjectContent}}
						<text style="font-weight: 500;">({{item.type==0?'单选':'多选'}})</text>
					</view>
				</view>
				<view class="question_option">
					<view :class="{option_item:true,active_option:items.id==items.active}"
						v-for="(items,indexs) in item.optionList" :key='indexs' @tap.stop="optionItem(items)">
						<view class="option_box">
							<image src="@/static/hook.png" mode=""></image>
						</view>
						<text>{{items.optionContent}}</text>
					</view>
				</view>
			</view>
			<view style="height: 180rpx;">
				<!-- 占位框,避免内容被提交按键遮挡 -->
			</view>
		</view>
		<!-- 底部提交按键,@tap.stop阻止冒泡事件 -->
		<view class="submit_box" @longpress="goAdmin">
			<button class="sub_btn" type="default" @tap.stop="subQuestion">提交</button>
		</view>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				baseUrl:'',
				active: 0,
				qusetionList: [],
			}
		},

		onLoad() {
			// 获取全局变量 baseUrl
			this.baseUrl = getApp().globalData.baseUrl;
			// 调用方法
			this.getData()
		},

		methods: {
			//获取用户信息
			getUserInfo(param) {},
			
			//获取题目、选项
			getData() {
				uni.request({
					url: this.baseUrl + 'query',
					method: "GET",
					data: {},
					success: (res) => {
						var arr =res.data.dataArr
						var dataList = arr.sort(this.compare('sort')) //按对象内的sort字段进行排序数组
						
						// 每个问卷都加上状态字段active
						for (let i in dataList) {
							var optionList = []
							for (let j in dataList[i].optionList) {
								dataList[i].optionList[j].active = ''
								optionList.push(dataList[i].optionList[j])
							}
							dataList[i].optionList = optionList
						}
						this.qusetionList = dataList
					},
					fail: () => {
						uni.showToast({
							title: "网络请求失败!",
							icon: 'none',
							duration: 2000
						})
					}
				})
			},
			
			//--- 数组内的对象按某个字段进行排序 ---//
			compare(property){
				return function(a,b){
					var value1 = a[property];
					var value2 = b[property];
					return value1 - value2;  //升序,  降序为value2 - value1
				}
			},
			
			// 选择及未选择样式切换
			optionItem(param) {
				// 根据每个字段的id作为唯一状态标识是否选中
				this.active = param.id
				for (var i in this.qusetionList) {
					// 单项选择
					if (this.qusetionList[i].type == 0) {
						if (this.qusetionList[i].groudId == param.subjectId) {
							for (var j in this.qusetionList[i].optionList) {
								if (this.qusetionList[i].optionList[j].id == param.id && this.qusetionList[i].optionList[j].active =='') {
									this.qusetionList[i].optionList[j].active = param.id
								} else {
									this.qusetionList[i].optionList[j].active = ''
								}
							}
						}
						// 多项选择
					} else if (this.qusetionList[i].type == 1) {
						for (var j in this.qusetionList[i].optionList) {
							if (this.qusetionList[i].optionList[j].id == param.id) {
								if (this.qusetionList[i].optionList[j].active == '') {
									this.qusetionList[i].optionList[j].active = param.id
								} else if (this.qusetionList[i].optionList[j].active != '') {
									this.qusetionList[i].optionList[j].active = ''
								}
							}
						}
					}
				}
			},
			
			// 提交问卷
			subQuestion() {
				var subTime = Date.now()
				var userName = '名字' + subTime.toString ().slice(-3)
				var activeQuestion = [] //已选择的数据列表
				
				// 循环判断active是否为空,单选和多选因为传参格式需要区分判断
				for (var i in this.qusetionList) {
					// 单选判断循环
					if (this.qusetionList[i].type == 0) {
						for (var j in this.qusetionList[i].optionList) {
							if (this.qusetionList[i].optionList[j].active != '') {
								// 把已选择的数据追加到列表
								activeQuestion.push({
									subTime:subTime,
									userName: userName,
									// groudId: this.qusetionList[i].groudId,
									sort: this.qusetionList[i].sort,
									subjectContent: this.qusetionList[i].subjectContent,
									optionContent: this.qusetionList[i].optionList[j].optionContent
								})
							}
						}
					} else {
						// 多选判断循环,选项ID以逗号拼接成字符串
						var optionArr = []
						for (var j in this.qusetionList[i].optionList) {
							if (this.qusetionList[i].optionList[j].active != '') {
								// optionArr.push(this.qusetionList[i].optionList[j].id)
								optionArr.push(this.qusetionList[i].optionList[j].optionContent)
							}
						}
						// 把已选择的数据追加到列表
						if (optionArr != '') {
							activeQuestion.push({
								subTime:subTime,
								userName: userName,
								// groudId: this.qusetionList[i].groudId,
								sort: this.qusetionList[i].sort,
								subjectContent: this.qusetionList[i].subjectContent,
								//optionId: optionArr.join()
								optionContent:optionArr.join()
							})
						}
					}
				}

				//console.log(activeQuestion)
				
				if(activeQuestion.length < this.qusetionList.length){
					uni.showToast({
						title: "问题还没有回答完!",
						icon: 'none',
						duration: 2000
					});
				} else {
					//提交数据给后端
					uni.request({
						url: this.baseUrl + 'addAnswer',
						method: 'POST',
						header: {'content-type' : "application/x-www-form-urlencoded"},
						data: {
							formData: JSON.stringify(activeQuestion) //转换为JSON格式字符串
						},
						success: (res) => {
							// 服务器返回数据,后续业务逻辑处理
							console.log(res)
							// 调用方法,刷新数据
							this.getData()
							uni.showToast({
								title: "保存成功", 
								icon : "success",
								duration:3000
							})
						},
						fail: (err) => {
							console.log(err)
							uni.showToast({ 
								title: "服务器响应失败,请稍后再试!", 
								icon : "none",
							})
						},
						complete: () => {
							
						}
					})
					
				}
			},
			
			// 跳转到页面
			goAdmin() {
				uni.navigateTo({
					url: '../admin/admin'
				})
			}
			
		}
	}
</script>

<style lang="less" scoped>
	.question {
		.question_header {
			// height: 90rpx;固定高度之后,长内容换行不能自动增加高度
			background-color: #f1f1f1;
			font-size: 34rpx;
			font-weight: 700;
			color: #333333;

			.header_title {
				width: 95%;
				margin-left: 37rpx;
				line-height: 90rpx;
			}
		}

		.question_option {
			width: 650rpx;
			margin-top: 7rpx;
			// background-color: #F0AD4E;
			display: flex;
			justify-content: space-between;
			flex-wrap: wrap;
			margin: 0 auto;
			margin-bottom: 40rpx;

			.option_item {
				width: 300rpx;
				margin-top: 34rpx;
				// background-color: #DD524D;
				font-size: 30rpx;
				color: #666666;
				display: flex;
				align-items: center;

				.option_box {
					width: 35rpx;
					height: 35rpx;
					border: 1rpx solid #999999;
					border-radius: 5px;
					margin-right: 10rpx;
					// background-color: #FF852A;
					display: flex;
					justify-content: center;
					align-items: center;

					image {
						width: 20rpx;
						height: 20rpx;
					}
				}
			}
		}
	}

	.active_option {
		.option_box {
			background: linear-gradient(-30deg, #ff7029 0%, #faa307 100%);
			border: 1rpx solid #faa307 !important;
		}

		text {
			color: #ff7029;
		}
	}

	.submit_box {
		width: 750rpx;
		height: 160rpx;
		background-color: #F1F1F1;
		position: fixed;
		bottom: 0;
	}

	.sub_btn {
		width: 80%;
		height: 88rpx;
		background: linear-gradient(-30deg, #dc4011 0%, #faa307 100%);
		border-radius: 44rpx;
		margin: 40rpx auto;
		font-size: 32rpx;
		font-weight: 700;
		color: #ffffff;
		text-align: center;
		line-height: 88rpx;
	}

	// 按钮原生会存在上下黑线,该属性去除
	button::after {
		border: none;
	}
</style>
  • 后台管理部分页面代码 charts.vue
<template>
	<view>
		<block v-for="(item,index) in dataList" :key="index">
			<view style="margin: 50rpx;">{{item.subjectContent}}</view>
			<canvas :canvas-id="'id'+index" style="width: 350px; height: 300px;" ></canvas>
		</block>
	</view>
</template>

<script>
	// 引入外部 js
	import canvas from '@/static/canvas.js'

	export default {
		data() {
			return {
				baseUrl: '',
				dataList: []
			}
		},
		onReady() {
			// 获取全局变量 baseUrl
			this.baseUrl = getApp().globalData.baseUrl;
			// 调用方法
			this.getData()
		},

		methods: {
			//从后端获取数据
			getData() {
				uni.showLoading({
					title: '数据加载中...'
				})
				uni.request({
					url: this.baseUrl + 'queryByGroup',
					method: "GET",
					data: {},
					success: (res) => {
						//console.log(res)
						let tempArr = res.data
						this.dataList = tempArr
						let arr = tempArr.sort(this.compare('sort')) //按对象内的sort字段进行排序数组

						// 延迟1秒等待canvas组件渲染完成,再调用方法绘画,否则绘画不成功
						setTimeout(function(){
							for (let x in arr) {
								// 调用外部方法并传入参数: canvas-id,数组,总数量
								canvas.canvasGraph('id'+x, arr[x].list, arr[x].list[0].total)
							}
						},1000)
					},
					fail: (err) => {
						uni.showToast({
							title: "网络请求失败!",
							icon: 'none',
							duration: 2000
						})
					},
					complete: () => {
						setTimeout(function(){
							uni.hideLoading()
						},1000)
					}
				})
			},
			
			//--- 数组内的对象按某个字段进行排序 ---//
			compare(property){
				return function(a,b){
					var value1 = a[property];
					var value2 = b[property];
					return value1 - value2;  //升序,  降序为value2 - value1
				}
			}
			
		}
	}
</script>

<style>

</style>
  • 后端使用 nodejs + mongoDB 搭建服务
  • 程序入口文件 app.js
const express = require('express');
const cors=require('cors');
const bodyParser = require('body-parser');
const app = express();

//全局变量,数据库地址
global.G_url = "mongodb://127.0.0.1:27017";

//处理跨域
app.use(cors()) 
//对post请求的请求体进行解析
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())

//设置share文件夹下的所有文件能通过网址访问,用作静态文件web服务
app.use(express.static("./share"))

//路由配置
const index=require('./routes/index.js')
const query=require('./routes/query.js')
const add=require('./routes/add.js')
const del=require('./routes/del.js')
const edit=require('./routes/edit.js')
const update=require('./routes/update.js')
const addAnswer=require('./routes/addAnswer.js')
const queryAnswer=require('./routes/queryAnswer.js')
const queryByGroup=require('./routes/queryByGroup.js')
const delAll=require('./routes/delAll.js')

app.use('/index',index)
app.use('/query',query)
app.use('/add',add)
app.use('/del',del)
app.use('/edit',edit)
app.use('/update',update)
app.use('/addAnswer',addAnswer)
app.use('/queryAnswer',queryAnswer)
app.use('/queryByGroup',queryByGroup)
app.use('/delAll',delAll)
 
//启动服务器
app.listen(3000,()=>{
  console.log('http://127.0.0.1:3000')
})
  • 对原始数据按题目名称进行分组,然后追加需要用到的字段,再把处理好的数据发给前端进行渲染。
// queryByGroup.js

const express = require('express');
const router = express.Router();
const MongoClient = require("mongodb").MongoClient;

const url = G_url; //G_url是全局变量,在app.js定义

router.get('/', function(req, res, next) {
	// 调用方法
	dataOperate()

	/*操作数据库,异步方法*/
	async function dataOperate() {
		var allArr = []
		var arr = null
		var conn = null

		try {
			conn = await MongoClient.connect(url)
			// 定义使用的数据库和表
			const dbo = conn.db("mydb").collection("answer")
			// 查询所有
			arr = await dbo.find().toArray()

			// 调用 byGroup方法对原始数组按指定字段进行分组
			let groupBySubjectContent = byGroup(arr, 'subjectContent')

			// 循环执行
			for (var n in groupBySubjectContent) {
				let subjectContent = groupBySubjectContent[n].subjectContent
				let nameList = groupBySubjectContent[n].list
				
				// 从原数组中过滤字段等于subjectContent ,取最后一个元素
				let lastArr = (arr.filter(item => item.subjectContent == subjectContent)).slice(-1)
				let sort = lastArr[0].sort

				// 计算数组中某个元素的累计数量
				let countedNameObj = nameList.reduce((prev, item) => {
					if (item in prev) {
						prev[item]++
					} else {
						prev[item] = 1
					}
					return prev
				}, {})

				// 一个对象分割为多个对象
				let list = []
				for (var key in countedNameObj) {
					var temp = {}
					temp.title = key
					temp.money = countedNameObj[key]
					list.push(temp)
				}

				// 所有对象 money字段求和
				let listSum = list.reduce((prev, item) => {
					prev += item.money
					return prev
				}, 0)

				// 对象循环追加键值对
				for (var k in list) {
					list[k].total = listSum
					list[k].value = (list[k].money / listSum).toFixed(4) //计算比例,保留4位小数
					list[k].color = randomColor(k) //指定颜色
					//list[k].color = '#' + ('00000' + (Math.random() * 0x1000000 << 0).toString(16)).substr(-6) //随机颜色
				}

				// 对象追加到数组
				allArr.push({
					"sort": sort,
					"subjectContent": subjectContent,
					"list": list
				})
			}

			//给前端返回数据
			res.send(allArr)
			
		} catch (err) {
			console.log("错误:" + err.message)
			
		} finally {
			//关闭数据库连接
			if (conn != null) conn.close()
		}
	}

	/**
	 * 数据按字段分组处理
	 * @param arr [Array] 被处理的数组
	 * @param group_key [String] 分组字段
	 */
	function byGroup(arr, group_key) {
		let map = {}
		let res = []

		for (let i = 0; i < arr.length; i++) {
			let ai = arr[i]
			if (!map[ai[group_key]]) {
				// map[ai[group_key]] = [ai] //原始代码
				//optionContent是要筛选出来的字段
				map[ai[group_key]] = ai.optionContent.split(',')
			} else {
				// map[ai[group_key]].push(ai) //原始代码
				// split()通过指定分隔符对字符串进行分割,生成新的数组; arr = [...arr, ...arr2]  数组合并
				map[ai[group_key]] = [...map[ai[group_key]], ...ai.optionContent.split(',')]
			}
		}
		
		Object.keys(map).forEach(item => {
			res.push({
				[group_key]: item,
				list: map[item]
			})
		})
		
		return res
	}

	/**随机指定颜色**/
	function randomColor(index) {
		let colorList = ["#63b2ee","#76da91","#f8cb7f","#7cd6cf","#f89588","#9192ab","#efa666","#7898e1","#eddd86","#9987ce","#76da91","#63b2ee"]
		// let index = Math.floor(Math.random() * colorList.length)
		return colorList[index]
	}

});

module.exports = router;

到了这里,关于uniapp + node.js 开发问卷调查小程序的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 问卷调查|在线问卷调查系统|基于Springboot的在线问卷调查系统设计与实现(源码+数据库+文档)

    在线问卷调查系统目录 目录 基于Springboot的在线问卷调查系统设计与实现 一、前言 二、系统设计 三、系统功能设计  1、问卷管理 2、 问卷调查管理 3、题目管理 4、 用户管理 四、数据库设计  1、实体ER图 五、核心代码  六、论文参考 七、最新计算机毕设选题推荐 八、源码

    2024年03月12日
    浏览(49)
  • java SSM问卷调查系统myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

    一、源码特点     java SSM问卷调查管理系统是一套完善的web设计系统(系统采用SSM框架进行设计开发,spring+springMVC+mybatis),对理解JSP java编程开发语言有帮助,系统具有完整的源代 码和数据库,系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发,数据库为Mysql5.

    2024年01月22日
    浏览(46)
  • 基于selenium实现自动填写问卷星的问卷调查

    废话不多说,直接上解决方案: 没用用过selenium的小朋友记得先安装配置一下: 谷歌浏览器驱动的安装及selenium的安装与使用 - 知乎  防止有人不看参数说明,再写一遍: 注意:由于时间有限,目前我只做了单选和多选这两类选择题的自动填写,后续有时间的话会继续更新其

    2024年02月04日
    浏览(52)
  • 求免费好用的问卷调查平台!

    在当今信息时代,了解客户需求和市场趋势对企业的发展至关重要。而问卷调查是一种常见、有效的数据收集方式。本文将介绍一款 专业好用的问卷调查工具 ——Zoho Survey。我们将从功能特点、用户体验、数据分析和安全性四个方面来探讨它为用户带来的价值。 Zoho Survey提供

    2024年02月09日
    浏览(40)
  • 调查问卷平台哪家好?

    在如今的数字化时代,问卷调查已成为企业和组织了解顾客需求、员工满意度以及市场趋势的重要工具。然而,在众多的在线调查工具中, 为什么我们要选择Zoho Survey? 1、多种问卷题型: Zoho Survey提供丰富多样的问题类型,包括单选题、多选题、文本题、评分题等。用户可

    2024年02月11日
    浏览(38)
  • 医院患者满意度调查问卷示例

    以下是一个简单的医院患者满意度调查问卷示例,供参考。请注意,实际的问卷可能需要根据医院的特定需求和目标进行定制。 个人信息(可选): 您的年龄: [填写您的年龄]岁 您的性别: [选择性别] 男性 / 女性 / 其他 1. 您在本次就诊中对医疗护理的满意度: 非常满意

    2024年02月01日
    浏览(48)
  • 调查问卷Type Form的集成

    Typeform是一家制作线上调查问卷的公司。 Muñoz 和 David Okuniev两人于2012年创作出一个更加动态、更具交互性的用户调查工具,每次只提一个问题,并且根据用户的回答为其呈现下一个问题,像和朋友间的对话一样,让用户在不知不觉中就完成了问卷。 Typeform将帮你获得有关产品

    2024年02月10日
    浏览(80)
  • 泰安柒柒:国外问卷调查都有哪些题?

    提到 问卷调查 我们并不陌生,它经常被用作调查市场 、 商品意见 等多种调查中。 不过,提到国外问卷调查,大家就比较陌生了。简单来说就是 国外的一些企业或机构为了改进自己的商品或服务,会列出一些问题来让大众回答,并用付费或抽奖调查的方式取得大量的用户数

    2024年02月03日
    浏览(41)
  • Vue+Element UI完成新建调查问卷

    先看看效果图: 添加填空题:  添加单选题、多选题: 对新增的题目可以上移、下移、编辑、删除操作:  效果大致就是这样,实现代码:    

    2024年02月11日
    浏览(36)
  • 【学习记录】SPSS问卷调查表分析法

    用excel将收集的问卷数据存储,并用SPSS进行数据分析 此例是将收集到的字符型数据转换为易于分析的数值型数据,将列明转换为有代表性的简明的字符数值组合 注:①字符型数据转换为数值型数据:excel中,“查找和选择”-“替换”-“全部替换” ②excel中列数据只保留数值

    2024年02月02日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包