投票创建页面实现
文件选择上传组件 uni-file-picker 扩展组件 安装
https://ext.dcloud.net.cn/plugin?name=uni-file-picker
日期选择器uni-datetime-picker组件 安装
https://ext.dcloud.net.cn/plugin?name=uni-datetime-picker
iconfont小图标
https://www.iconfont.cn/
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;
}
vote
package com.java1234.entity;import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lombok.Data;import java.util.Date;
import java.util.List;/*** 投票实体* @author java1234_小锋 (公众号:java1234)* @site www.java1234.vip* @company 南通小锋网络科技有限公司*/
@TableName("t_vote")
@Data
public class Vote {private Integer id; // 编号private String title; // 标题private String explanation; // 投票说明private String coverImage; // 封面图片@JsonSerialize(using=CustomDateTimeSerializer.class)@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")private Date voteEndTime; // 投票结束时间private String openid; // 投票发起人openid@TableField(select=false,exist = false)private List<VoteItem> voteItemList;@TableField(select=false,exist = false)private WxUserInfo wxUserInfo;private Integer type=1; // 1 文字投票 2 图片投票}
VoteMapper
package com.java1234.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.java1234.entity.Vote;/*** 投票Mapper接口*/
public interface VoteMapper extends BaseMapper<Vote> {
}
VoteItemMapper
package com.java1234.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.java1234.entity.VoteItem;/*** 投票选项Mapper接口*/
public interface VoteItemMapper extends BaseMapper<VoteItem> {
}
IVoteItemService
package com.java1234.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.java1234.entity.VoteItem;/*** 投票选项Service接口*/
public interface IVoteItemService extends IService<VoteItem> {
}
IVoteService
package com.java1234.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.java1234.entity.Vote;/*** 投票Service接口*/
public interface IVoteService extends IService<Vote> {
}
IVoteItemServiceImpl
package com.java1234.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.java1234.entity.VoteItem;
import com.java1234.mapper.VoteItemMapper;
import com.java1234.service.IVoteItemService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;/*** 投票选项Service实现类* @author java1234_小锋 (公众号:java1234)* @site www.java1234.vip* @company 南通小锋网络科技有限公司*/
@Service("voteItemService")
public class IVoteItemServiceImpl extends ServiceImpl<VoteItemMapper,VoteItem> implements IVoteItemService {@Autowiredprivate VoteItemMapper voteItemMapper;}
IVoteServiceImpl
package com.java1234.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.java1234.entity.Vote;
import com.java1234.mapper.VoteMapper;
import com.java1234.service.IVoteService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;/*** 投票Service实现类* @author java1234_小锋 (公众号:java1234)* @site www.java1234.vip* @company 南通小锋网络科技有限公司*/
@Service("voteService")
public class IVoteServiceImpl extends ServiceImpl<VoteMapper, Vote> implements IVoteService {@Autowiredprivate VoteMapper voteMapper;
}
VoteController
package com.java1234.controller;import com.java1234.entity.R;
import com.java1234.entity.Vote;
import com.java1234.entity.VoteItem;
import com.java1234.service.IVoteItemService;
import com.java1234.service.IVoteService;
import com.java1234.util.DateUtil;
import com.java1234.util.JwtUtils;
import io.jsonwebtoken.Claims;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** 投票Controller控制器* @author java1234_小锋 (公众号:java1234)* @site www.java1234.vip* @company 南通小锋网络科技有限公司*/
@RestController
@RequestMapping("/vote")
public class VoteController {@Value("${coverImagesFilePath}")private String coverImagesFilePath;@Autowiredprivate IVoteService voteService;@Autowiredprivate IVoteItemService voteItemService;/*** 上传封面图片* @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;}/*** 添加投票* @param vote* @param token* @return*/@RequestMapping("/add")@Transactionalpublic R add(@RequestBody Vote vote, @RequestHeader String token){Claims claims = JwtUtils.validateJWT(token).getClaims();vote.setOpenid(claims.getId());voteService.save(vote);List<VoteItem> voteItemList = vote.getVoteItemList();for(VoteItem voteItem:voteItemList){voteItem.setVoteId(vote.getId());voteItem.setNumber(0);voteItemService.save(voteItem);}return R.ok();}
}
前端验证以及提交:
submitVote:async function(e){// 验证if(isEmpty(this.title)){uni.showToast({icon:"error",title:"请填写投票标题"})return;}// 投票选项片段 至少2个选项let resultOptions=this.options.filter(function(value,index,self){ // 过滤掉名称为空的投票选项console.log("value="+value.name)return !isEmpty(value.name)})console.log("xx"+JSON.stringify(resultOptions));console.log("length="+resultOptions.length)if(resultOptions.length<2){uni.showToast({icon:"error",title:"请至少填写两个投票选项"})return;}// 提交表单let form={title:this.title,coverImage:this.coverImageFileName,explanation:this.explanation,voteEndTime:this.voteEndTime,voteItemList:resultOptions,type:1}const result=await requestUtil({url:"/vote/add",data:form,method:"post"});if(result.code==0){console.log("发布成功")uni.showToast({icon:"success",title:"投票发起成功!"})}
}
dateUtil.js
// 判断传入日期是否和当前日期比较 const judgeDate=(toDate)=>{return new Date().getTime()-new Date(toDate).getTime();
}var timeFormat = function (msTime) {let time = new Date(msTime);let yy = time.getFullYear();let MM = time.getMonth() + 1;let dd = time.getDate();let hh = time.getHours() < 10 ? "0" + time.getHours() : time.getHours();let min =time.getMinutes() < 10 ? "0" + time.getMinutes() : time.getMinutes();let sec =time.getSeconds() < 10 ? "0" + time.getSeconds() : time.getSeconds();return yy + "-" + MM + "-" + dd + " " + hh + ":" + min + ":" + sec;
}export {timeFormat,judgeDate}
数据库
/*
SQLyog Ultimate v11.33 (64 bit)
MySQL - 5.7.18-log : Database - db_vote3
*********************************************************************
*//*!40101 SET NAMES utf8 */;/*!40101 SET SQL_MODE=''*/;/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`db_vote3` /*!40100 DEFAULT CHARACTER SET utf8 */;USE `db_vote3`;/*Table structure for table `t_vote` */DROP TABLE IF EXISTS `t_vote`;CREATE TABLE `t_vote` (`id` int(11) NOT NULL AUTO_INCREMENT,`title` varchar(600) DEFAULT NULL,`explanation` varchar(3000) DEFAULT NULL,`cover_image` varchar(600) DEFAULT NULL,`vote_end_time` datetime DEFAULT NULL,`openid` varchar(600) DEFAULT NULL,`type` int(11) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;/*Data for the table `t_vote` */insert into `t_vote`(`id`,`title`,`explanation`,`cover_image`,`vote_end_time`,`openid`,`type`) values (1,'2','2','20230516092542000000157.jpg','2023-05-17 09:25:33','o30ur5JpAsAUyGBkR0uW4IxvahR8',1);/*Table structure for table `t_vote_item` */DROP TABLE IF EXISTS `t_vote_item`;CREATE TABLE `t_vote_item` (`id` int(11) NOT NULL AUTO_INCREMENT,`vote_id` int(11) DEFAULT NULL,`name` varchar(600) DEFAULT NULL,`image` varchar(600) DEFAULT NULL,`number` int(11) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;/*Data for the table `t_vote_item` */insert into `t_vote_item`(`id`,`vote_id`,`name`,`image`,`number`) values (1,1,'1',NULL,0),(2,1,'2',NULL,0);/*Table structure for table `t_wxuserinfo` */DROP TABLE IF EXISTS `t_wxuserinfo`;CREATE TABLE `t_wxuserinfo` (`id` int(11) NOT NULL AUTO_INCREMENT,`openid` varchar(90) DEFAULT NULL,`nick_name` varchar(150) DEFAULT NULL,`avatar_url` varchar(600) DEFAULT NULL,`register_date` datetime DEFAULT NULL,`last_login_date` datetime DEFAULT NULL,`status` char(3) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8;/*Data for the table `t_wxuserinfo` */insert into `t_wxuserinfo`(`id`,`openid`,`nick_name`,`avatar_url`,`register_date`,`last_login_date`,`status`) values (7,'o30ur5PiPOr52bBsetXcIV93NL-U','小锋四号@java1234','20230410102248000000487.jpg','2023-04-10 10:21:30','2023-05-04 21:20:38','0'),(9,'o30ur5JpAsAUyGBkR0uW4IxvahR0','微信用户','default.png','2023-04-30 07:42:19','2023-04-30 07:42:19','1'),(10,'1',NULL,NULL,NULL,NULL,'1'),(11,'2',NULL,NULL,NULL,NULL,'1'),(12,'3',NULL,NULL,NULL,NULL,'1'),(13,'4',NULL,NULL,NULL,NULL,'1'),(14,'5',NULL,NULL,NULL,NULL,'1'),(15,'6',NULL,NULL,NULL,NULL,'1'),(16,'7',NULL,NULL,NULL,NULL,'1'),(17,'8',NULL,NULL,NULL,NULL,'1'),(19,'o30ur5JpAsAUyGBkR0uW4IxvahR8','小锋111@java1234','20230514112056000000757.jpeg','2023-05-11 08:44:11','2023-05-16 09:25:31','0');/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;