
HarmonyOS ArkTS 实战实现一个校园投票与问卷调查应用项目效果本文使用 HarmonyOS 和 ArkTS 实现一个校园投票与问卷调查应用。应用可以发起投票和问卷参与投票答题查看实时统计结果并提供问卷分类、参与状态筛选和结果可视化等功能。项目使用 DevEco Studio 开发适配 API 23 及以上版本。运行效果功能介绍本项目实现了以下功能发起投票/问卷设置投票标题和选项设置单选/多选设置截止时间参与投票提交问卷答案查看实时结果查看投票统计按状态筛选按类型筛选统计进行中、已结束、我参与的数量匿名投票支持定义数据结构首先定义投票和投票选项的数据结构interfaceVoteOption{id:number;text:string;votes:number;voters:string[];}interfaceVote{id:number;title:string;description:string;type:string;isMultiple:boolean;isAnonymous:boolean;creator:string;createTime:string;endTime:string;status:string;options:VoteOption[];totalVotes:number;}字段说明如下VoteOption投票选项id选项编号text选项内容votes票数voters投票人列表Vote投票/问卷id投票编号title标题description描述type类型投票/问卷/评选isMultiple是否多选isAnonymous是否匿名creator发起人createTime创建时间endTime截止时间status状态进行中/已结束options选项列表totalVotes总票数初始化页面状态使用State保存输入内容、类型选择、筛选条件StateprivatetitleText:string;StateprivatedescText:string;StateprivateendTimeText:string;StateprivateoptionTexts:string[][,];StateprivateselectedType:string投票;StateprivateisMultiple:booleanfalse;StateprivateisAnonymous:booleanfalse;StateprivatefilterStatus:string全部;StateprivatecurrentUserId:string2023001;StateprivatenextVoteId:number5;StateprivatenextOptionId:number20;StateprivateselectedOptions:number[][];准备一些初始投票数据Stateprivatevotes:Vote[][{id:1,title:校园十佳歌手投票,description:选出你心中的校园十佳歌手每人可投3票,type:评选,isMultiple:true,isAnonymous:false,creator:学生会,createTime:2026-07-10,endTime:2026-07-25,status:进行中,totalVotes:256,options:[{id:1,text:1号选手 张三,votes:89,voters:[]},{id:2,text:2号选手 李四,votes:76,voters:[]},{id:3,text:3号选手 王五,votes:91,voters:[2023001]}]},{id:2,title:食堂新增菜品调查,description:你最希望食堂新增什么菜品,type:问卷,isMultiple:false,isAnonymous:true,creator:后勤处,createTime:2026-07-12,endTime:2026-07-20,status:进行中,totalVotes:189,options:[{id:4,text:麻辣香锅,votes:67,voters:[]},{id:5,text:螺蛳粉,votes:82,voters:[]},{id:6,text:汉堡薯条,votes:40,voters:[]}]},{id:3,title:运动会吉祥物投票,description:选择你喜欢的运动会吉祥物设计方案,type:投票,isMultiple:false,isAnonymous:false,creator:体育部,createTime:2026-07-01,endTime:2026-07-10,status:已结束,totalVotes:512,options:[{id:7,text:方案A运动小狮子,votes:234,voters:[]},{id:8,text:方案B奔跑小鹿,votes:278,voters:[]}]}];发起投票用户可以发起新的投票privatecreateVote():void{consttitlethis.titleText.trim();constdescthis.descText.trim();constendTimethis.endTimeText.trim();constvalidOptionsthis.optionTexts.map(tt.trim()).filter(tt.length0);if(title.length0||validOptions.length2){return;}constoptions:VoteOption[]validOptions.map(text({id:this.nextOptionId,text,votes:0,voters:[]}));constvote:Vote{id:this.nextVoteId,title,description:desc,type:this.selectedType,isMultiple:this.isMultiple,isAnonymous:this.isAnonymous,creator:我,createTime:newDate().toISOString().split(T)[0],endTime:endTime||2026-12-31,status:进行中,totalVotes:0,options};this.votes[vote,...this.votes];this.nextVoteId1;this.titleText;this.descText;this.endTimeText;this.optionTexts[,];this.isMultiplefalse;this.isAnonymousfalse;}至少需要2个选项才能创建投票。添加选项创建投票时可以添加更多选项privateaddOption():void{if(this.optionTexts.length10){this.optionTexts[...this.optionTexts,];}}privateupdateOptionText(index:number,text:string):void{constnewTexts[...this.optionTexts];newTexts[index]text;this.optionTextsnewTexts;}最多支持10个选项。参与投票用户可以选择选项进行投票privatetoggleOption(optionId:number):void{if(this.selectedOptions.includes(optionId)){this.selectedOptionsthis.selectedOptions.filter(idid!optionId);}else{if(this.isMultiple){this.selectedOptions[...this.selectedOptions,optionId];}else{this.selectedOptions[optionId];}}}privatesubmitVote(voteId:number):void{if(this.selectedOptions.length0){return;}this.votesthis.votes.map((vote:Vote){if(vote.idvoteIdvote.status进行中){consthasVotedvote.options.some(oo.voters.includes(this.currentUserId));if(hasVoted)returnvote;constupdatedOptionsvote.options.map((opt:VoteOption){if(this.selectedOptions.includes(opt.id)){return{id:opt.id,text:opt.text,votes:opt.votes1,voters:[...opt.voters,this.currentUserId]};}returnopt;});return{id:vote.id,title:vote.title,description:vote.description,type:vote.type,isMultiple:vote.isMultiple,isAnonymous:vote.isAnonymous,creator:vote.creator,createTime:vote.createTime,endTime:vote.endTime,status:vote.status,options:updatedOptions,totalVotes:vote.totalVotesthis.selectedOptions.length};}returnvote;});this.selectedOptions[];}单选只能选一个多选可以选多个每人只能投一次。结束投票发起人可以手动结束投票privateendVote(voteId:number):void{this.votesthis.votes.map((vote:Vote){if(vote.idvoteIdvote.status进行中){return{id:vote.id,title:vote.title,description:vote.description,type:vote.type,isMultiple:vote.isMultiple,isAnonymous:vote.isAnonymous,creator:vote.creator,createTime:vote.createTime,endTime:vote.endTime,status:已结束,options:vote.options,totalVotes:vote.totalVotes};}returnvote;});}筛选投票支持按状态和类型筛选privategetFilteredVotes():Vote[]{if(this.filterStatus全部){returnthis.votes;}if(this.filterStatus我参与的){returnthis.votes.filter((v:Vote)v.options.some(oo.voters.includes(this.currentUserId)));}returnthis.votes.filter((v:Vote)v.statusthis.filterStatus);}筛选按钮封装BuilderFilterButton(text:string){Button(text).height(32).padding({left:14,right:14}).fontSize(12).fontColor(this.filterStatustext?Color.White:#344054).backgroundColor(this.filterStatustext?#9333EA:#F3E8FF).borderRadius(16).onClick((){this.filterStatustext;});}计算选项百分比计算每个选项的得票百分比privategetPercentage(votes:number,total:number):number{if(total0)return0;returnMath.round((votes/total)*100);}用于进度条展示投票结果。统计数据统计进行中、已结束、我参与的数量privategetActiveCount():number{returnthis.votes.filter((v:Vote)v.status进行中).length;}privategetEndedCount():number{returnthis.votes.filter((v:Vote)v.status已结束).length;}privategetMyVotedCount():number{returnthis.votes.filter((v:Vote)v.options.some(oo.voters.includes(this.currentUserId))).length;}顶部统计区域展示总投票、进行中、已结束、我参与的this.StatCard(总投票,${this.votes.length},#9333EA,#FAF5FF);this.StatCard(进行中,${this.getActiveCount()},#16A34A,#F0FDF4);this.StatCard(已结束,${this.getEndedCount()},#6B7280,#F3F4F6);this.StatCard(我参与,${this.getMyVotedCount()},#2563EB,#EFF6FF);设置状态颜色不同状态使用不同颜色privategetStatusColor(status:string):ResourceColor{if(status进行中){return#16A34A;}return#6B7280;}privategetStatusBgColor(status:string):ResourceColor{if(status进行中){return#DCFCE7;}return#F3F4F6;}绿色进行中灰色已结束紫色页面主题色使用列表展示投票使用List和ForEach渲染投票列表List({space:12}){ForEach(this.getFilteredVotes(),(vote:Vote){ListItem(){this.VoteCard(vote)}},(vote:Vote)vote.id.toString());}.width(100%).layoutWeight(1).scrollBar(BarState.Off);每个投票卡片包含标题、描述、发起人、截止时间、状态、选项列表带进度条和投票按钮。页面设计说明应用使用紫色作为主题色体现投票民主、庄重的氛围。页面主要分为以下区域顶部标题数据统计区域发起投票表单状态筛选区域投票列表投票选择弹窗页面采用浅灰色背景和白色卡片。投票结果使用彩色进度条直观展示各选项占比选项选中状态使用紫色勾选标记单选/多选使用不同图标区分。SDK 配置本项目使用 HarmonyOS API 24满足 API 23 及以上要求{ name: default, compatibleSdkVersion: 6.1.1(24), runtimeOS: HarmonyOS, targetSdkVersion: 6.1.1(24), compileSdkVersion: 6.1.1(24) }entry 模块中的运行系统也要保持一致{ apiType: stageMode, targets: [ { name: default, runtimeOS: HarmonyOS } ] }运行项目使用 DevEco Studio 打开项目然后找到entry/src/main/ets/pages/Index.ets等待项目同步完成点击右侧的Preview按钮即可查看应用效果。项目总结本文使用 HarmonyOS 和 ArkTS 实现了一个校园投票与问卷调查应用。项目实现了发起投票、添加选项、单选多选、匿名投票、参与投票、实时结果统计、进度条展示、状态筛选等功能。通过这个项目可以掌握ArkTS 接口定义和嵌套数据结构State状态管理投票逻辑和防重复投票List和ForEach列表渲染百分比计算和进度条动态添加选项自定义Builder组件HarmonyOS 投票类应用布局后续还可以加入图片投票、评论功能、投票分享、定时自动结束、结果导出Excel、问卷模板、必填项设置和数据可视化图表等功能。