锋哥原创的uniapp微信小程序投票系统实战:
uniapp微信小程序投票系统实战课程 (SpringBoot2+vue3.2+element plus ) ( 火爆连载更新中... )_哔哩哔哩_bilibiliuniapp微信小程序投票系统实战课程 (SpringBoot2+vue3.2+element plus ) ( 火爆连载更新中... )共计21条视频,包括:uniapp微信小程序投票系统实战课程 (SpringBoot2+vue3.2+element plus ) ( 火爆连载更新中... )、第2讲 投票项目后端架构搭建、第3讲 小程序端 TabBar搭建等,UP主更多精彩视频,请关注UP账号。https://www.bilibili.com/video/BV1ea4y137xf/
文件选择上传组件 uni-file-picker 扩展组件 安装
uni-file-picker 文件选择上传 - DCloud 插件市场
日期选择器uni-datetime-picker组件 安装
uni-datetime-picker 日期选择器 - DCloud 插件市场
iconfont小图标
iconfont-阿里巴巴矢量图标库
iconfont.css
@font-face {
font-family: 'iconfont'; /* Project id 3888696 */
src: url('//at.alicdn.com/t/c/font_3888696_rjermxmgmb.woff2?t=1680049466852') format('woff2'),
url('//at.alicdn.com/t/c/font_3888696_rjermxmgmb.woff?t=1680049466852') format('woff'),
url('//at.alicdn.com/t/c/font_3888696_rjermxmgmb.ttf?t=1680049466852') format('truetype');
}
.share {
font-family: iconfont;
margin-left: 20rpx;
font-size: 26rpx;
color: blue;
}
.uploadImg{
font-family: iconfont;
font-size: 56rpx;
color: #acacac;
}
.smallUploadImg{
font-family: iconfont;
font-size: 36rpx;
color: #acacac;
}
.removeOption{
font-family: iconfont;
font-size: 38rpx;
color: red;
padding-right: 10px;
}
.addOption{
font-family: iconfont;
font-size: 38rpx;
padding-right: 10px;
}
.chooseOption{
font-family: iconfont;
font-size: 26rpx;
}
.voteListItem{
font-family: iconfont;
font-size: 26rpx;
}
.voteManageItem{
font-family: iconfont;
font-size: 46rpx;
color: blue;
padding-bottom: 8px;
}
前端代码:
<template>
<view class="word_vote">
<view class="cover_img">
<view class="title_tip">
<view class="cover">
封面图(可以不上传)
</view>
<view class="tip">
( 宽高比:650 × 300 )
</view>
</view>
<view class="upload_img">
<uni-file-picker
@select="selectCoverFileFunc($event)"
:auto-upload="false"
limit="1"
:del-icon="false"
disable-preview
file-mediatype="image"
:imageStyles="coverImageStyles">
<view class="upload">
<text class="uploadImg"></text>
</view>
</uni-file-picker>
</view>
</view>
<view class="basic_settings">
<view class="title_tip">
<view class="title">
基础设置
</view>
</view>
<view class="settings">
<view class="title">
<input type="text" v-model="title" placeholder="填写投票标题" placeholder-style="color:#bababa;font-size:16px"/>
</view>
<view class="explanation">
<textarea v-model="explanation" placeholder="投票说明 (非必填)" placeholder-style="color:#bababa;font-size:14px"></textarea>
</view>
</view>
</view>
<view class="vote_options_settings">
<view class="title_tip">
<view class="title">
投票选项设置
</view>
</view>
<view class="option_list">
<view class="option_item" v-for="(item,index) in options" :key="item.id">
<text class="removeOption" @click="removeOption(item.id)"></text><input type="text" v-model="item.name" placeholder="输入选项名称" placeholder-style="color:#bababa;font-size:14px">
</view>
</view>
<view class="option_add" @click="addOption()">
<text class="addOption"></text><text>添加选项</text>
</view>
</view>
<view class="vote_rules_settings">
<view class="title_tip">
<view class="title">
投票规则设置
</view>
</view>
<view class="rule_list">
<view class="rule_item">
<text>投票截止时间</text>
<view >
<uni-datetime-picker
:border="false"
:clear-icon="false"
v-model="voteEndTime"
:start="startDate"
:end="endDate"
></uni-datetime-picker>
</view>
</view>
</view>
</view>
</view>
<view class="vote_btn" >
<button type="primary" @click="submitVote">发起投票</button>
</view>
</template>
<script>
import {getBaseUrl, requestUtil} from "../../utils/requestUtil.js"
import {isEmpty} from "../../utils/stringUtil.js"
import {timeFormat} from "../../utils/dateUtil.js"
export default{
data(){
const curDate=new Date();
const vv=new Date(curDate.getTime()+24*60*60*1000);
return{
title:'',
explanation:'',
coverImageFileName:'',
coverImageStyles: {
width:"700rpx",
height:"400rpx",
border:false
},
voteEndTime:timeFormat(vv),
options:[
{
id:1,
name:''
},
{
id:2,
name:''
}
]
}
},
computed:{
startDate(){
return new Date();
},
endDate(){
const curDate=new Date();
const vv=new Date(curDate.getTime()+24*60*60*1000*365);
return vv;
}
},
methods:{
addOption:function(){
var option={
id:this.options[this.options.length-1].id+1,
name:''
}
this.options.push(option);
},
removeOption:function(id){
const index=this.options.findIndex(v=>v.id===id)
this.options.splice(index,1);
},
selectCoverFileFunc:function(e){
console.log(e.tempFilePaths[0])
uni.uploadFile({
header:{token:uni.getStorageSync("token")},
url:getBaseUrl()+"/vote/uploadCoverImage",
filePath:e.tempFilePaths[0],
name:"coverImage",
success: (res) => {
let result=JSON.parse(res.data);
if(result.code==0){
this.coverImageFileName=result.coverImageFileName;
}
}
})
}
}
}
</script>
<style lang="scss">
@import "/common/css/iconfont.css";
.word_vote{
padding: 20px;
padding-bottom: 70px;
.cover_img{
.title_tip{
margin-left: 10rpx;
font-size: 26rpx;
color: gray;
display: flex;
justify-content: space-between;
}
.upload_img{
border-radius: 5px;
margin-top: 20rpx;
width:100%;
height: 360rpx;
background-color: white;
display: flex;
align-items: center;
justify-content: center;
.upload{
margin: 10rpx;
background-color: #f4f5f7;
width:90%;
height: 80%;
display: flex;
align-items: center;
justify-content: center;
}
}
}
.basic_settings{
margin-top: 20px;
.title_tip{
margin-left: 10rpx;
font-size: 26rpx;
color: gray;
margin-bottom: 10px;
.title{
}
}
.settings{
border-radius: 5px;
background-color: white;
.title{
padding: 10px;
input{
font-size: 1.3rem;
border-bottom: 1px solid #e4e4e4;
padding-bottom: 15px;
}
}
.explanation{
padding: 10px;
textarea{
height: 100px;
}
}
}
}
.vote_options_settings{
margin-top: 20px;
.title_tip{
margin-left: 10rpx;
font-size: 26rpx;
color: gray;
margin-bottom: 10px;
.title{
}
}
.option_list{
.option_item{
margin-top: 10px;
border-radius: 5px;
background-color: white;
padding: 10px;
display: flex;
}
}
.option_add{
margin-top: 10px;
border-radius: 5px;
background-color: white;
padding: 10px;
display: flex;
color:blue;
font-size:14px
}
}
.vote_rules_settings{
margin-top: 20px;
.title_tip{
margin-left: 10rpx;
font-size: 26rpx;
color: gray;
margin-bottom: 10px;
.title{
}
}
.rule_list{
border-radius: 5px;
background-color: white;
.rule_item{
display: flex;
justify-content: space-between;
padding: 12px;
border-bottom: 1px solid #e4e4e4;
font-size: 28rpx;
align-items: center;
height: 45rpx;
}
}
}
}
.vote_btn{
height: 120rpx;
width: 100%;
background-color: white;
position: fixed;
bottom: 0;
border-top: 1px solid #e4e4e4;
button{
margin: 10px;
}
}
</style>
后端:
coverImagesFilePath: D://uniapp/coverImgs/
封面上传:
/**
* 上传封面图片
* @param coverImage
* @return
* @throws Exception
*/
@RequestMapping("/uploadCoverImage")
public Map<String,Object> uploadCoverImage(MultipartFile coverImage)throws Exception{
System.out.println("filename:"+coverImage.getName());
Map<String,Object> resultMap=new HashMap<>();
if(!coverImage.isEmpty()){
// 获取文件名
String originalFilename = coverImage.getOriginalFilename();
String suffixName=originalFilename.substring(originalFilename.lastIndexOf("."));
String newFileName= DateUtil.getCurrentDateStr()+suffixName;
FileUtils.copyInputStreamToFile(coverImage.getInputStream(),new File(coverImagesFilePath+newFileName));
resultMap.put("code",0);
resultMap.put("msg","上传成功");
resultMap.put("coverImageFileName",newFileName);
}
return resultMap;
}