ktv管理系统_7天撸完KTV点歌系统,含后台管理系统(完整版)
最近手有点痒琢磨着做个啥,朝思暮想还是写个KTV点歌系统,模拟了一下KTV开户的思路,7天累死我了,不过技术点还挺多的,希望你可以看完(〜^㉨^)〜
用Node(Express)教你写KTV点歌系统,包括前台内容和后台管理系统,整合Express框架和Mongodb数据库服务器开发;教你用Vue.JS,ElementUI和iViewUI写出超漂亮的页面,随心点歌随心听
思维导图
技术栈
- 后端: Express + Mongodb + jsonwebtoken等等
- 前端: Vue.JS + ElementUI + iViewUI + Axios等等
功能介绍
本项目分前台开发,后台开发和服务器开发
- 用户听歌需要登录(路由守卫)
- 用户需要到管理员申请账号和密码
- 用户登录听歌(风格点歌,语种点歌,明星点歌,热门歌曲等等...)
- 剩余时长30分钟提醒,到时间自动下机
- 管理员对歌曲的增删改查
- 管理员给用户开户,可以选择上机的时间
- 管理员查看订单,删除订单,搜索订单
- 管理员收藏歌曲,推荐到ktv推荐歌曲
- 等等...
项目设计结构
--
-- 后台管理系统架构
ktv-admin
├── README.md
├── public
| ├── index.html -- vue挂载页面
| └── ** -- 你可以在这里链接少量静态资源
├── src -- 开发文件夹
| ├── App.vue -- Vue挂载根页面
| ├── main.js -- Vue程序入口文件,挂载各种组件
| ├── router.js -- Vue路由配置文件
| ├── store.js -- Vuex的状态管理文件
| ├── assets -- 静态资源文件夹
| ├── components --公共组件
| | └── nav.vue -- 后台导航栏
| ├── plugins --插件
| | ├── axios.js -- 配置跨域,拦截器等等
| | ├── Date.js -- 格式化日期
| | └── wsmLoading.js -- 加载动画Loading
| ├── stores -- 状态管理文件夹
| | └── adminStore.js -- 管理员状态
| ├── views -- 页面文件夹
| | ├── 404.vue -- 404页面
| | ├── adminlikes.vue -- 管理员处理ktv收藏歌曲
| | ├── allorders.vue -- 订单管理
| | ├── Home.vue -- 后台根页面
| | ├── Index.vue -- 后台首页
| | ├── managemusic.vue -- 音乐管理
| | ├── user_service.vue -- 给用户开户
| | └── login.vue -- 后台登录
└── babel.config.js -- babel配置
-- 前台用户听歌架构
ktv-client
├── README.md
├── public
| ├── index.html -- vue挂载页面
| └── ** -- 你可以在这里链接少量静态资源
├── src -- 开发文件夹
| ├── App.vue -- Vue挂载根页面
| ├── main.js -- Vue程序入口文件,挂载各种组件
| ├── router.js -- Vue路由配置文件
| ├── store.js -- Vuex的状态管理文件
| ├── assets -- 静态资源文件夹
| ├── components --公共组件
| | ├── bottomNav.vue -- 底部音乐控制区域
| | └── topNav.vue -- 顶部信息区域
| ├── config --配置
| | ├── addSong.js --封装选取歌曲方法
| | ├── isBadAccount.js --验证账户合法性
| | ├── isLogin.js --是否登录
| | ├── nextSong.js --封装下一首歌曲方法
| | └── prevSong.js --封装上一首歌曲方法
| ├── plugins --插件
| | ├── axios.js -- 配置跨域,拦截器等等
| | └── wsmLoading.js -- 加载动画Loading
| ├── stores -- 状态管理文件夹
| | └── song.js -- 存储歌曲信息
| ├── views -- 页面文件夹
| | ├── 404.vue -- 404页面
| | ├── abc.vue -- 拼音点歌
| | ├── artist.vue -- 明星点歌
| | ├── Home.vue -- 后台根页面
| | ├── Index.vue -- 后台首页
| | ├── hot.vue -- 热播歌曲
| | ├── ktvlikes.vue -- ktv推荐歌曲
| | ├── selected.vue -- 已选歌曲
| | ├── style.vue -- 风格点歌
| | └── language.vue -- 语种点歌
├── babel.config.js -- babel配置
└── vue.config.js -- vue配置
项目启动介绍
首先
1. 首先不要改变服务器端口,否则报错.
2. 你需要在装有Node和Vue的环境中测试,如果其中一个没有请先下载([Node下载](Node.js),[Vue下载](安装 — Vue.js)).
3. 首先在最外层文件夹下载依赖:npm install 下载后端依赖,
4. 接着进入ktv-client, npm install 下载用户前端依赖.
5. 接着进入ktv-admin, npm install 下载管理员前端依赖.
6. 以上工作完成后,使用命令`npm run server 或者 node index`命令启动Node服务器,启动成功会显示:
**Server is running on port [8633].**
**Mongodb is Connected.Please have a great coding.**
7. 进入ktv-client,打开命令板,使用命令`npm run client`启动前台用户项目,启动成功后用浏览器访问`http://localhost:xxxx`
8. 进入ktv-admin,打开命令板,使用命令`npm run admin`启动后台管理系统项目,启动成功后用浏览器访问`http://localhost:xxxx`
9. 本例中将Mongodb部署在本地电脑上,如果你仔细阅读了这篇文档,启动项目应该是很容易的。如果你把Mongodb部署在其他地方,请自行修改`secret/mongodbURI.js`配置文件信息。
10.项目启动成功
接着
postman注册管理员
技术攻关
Date方法
由于脑袋不好使的原因加上js没有元素格式化日期的方法,就瞎掰一个(值得学习)
Date.js
/**
*
* @author: Mr_Wei
* @version: 1.0.0
* @description: 格式化日期
* @Date: 2019/10/16 09:32
*
*/ Date.prototype.format = function(format) {var o = {"M+": this.getMonth() + 1, //月份"d+": this.getDate(), //日"H+": this.getHours(), //小时"m+": this.getMinutes(), //分"s+": this.getSeconds(), //秒"q+": Math.floor((this.getMonth() + 3) / 3), //季度"f+": this.getMilliseconds() //毫秒};if (/(y+)/.test(format))format = format.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));for (var k in o)if (new RegExp("(" + k + ")").test(format))format = format.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));return format;
}export default Date.prototype.format然后我们使用其格式日期
require(Date);
// const now = new Date().format("yyyy/MM/dd HH:mm:ss.S");
const now = new Date().format("yyyy/MM/dd HH:mm:ss");
验证码(svg-captcha)
svg-captcha验证码的运用,防止暴力破解密码,加强安全性.
详细的文档地址:svg-captcha
使用验证码
```
// 后台生成验证码
router.get("/getCaptcha", (req, res) => {var captcha = svgCaptcha.create({ // 翻转颜色 inverse: false, // 字体大小 fontSize: 38, // 噪声线条数 noise: 3, // 宽度 width: 80, // 高度 height: 32, }); // 保存到session,忽略大小写 req.session = captcha.text.toLowerCase(); console.log(req.session); //0xtg 生成的验证码//保存到cookie 方便前端调用验证res.cookie('captcha', req.session); res.setHeader('Content-Type', 'image/svg+xml');res.send(String(captcha.data));res.end();
})// 前台获取验证码
--HTML
<img width="80" style="background:#EEE9E9;margin-left:30px;" ref="captcha" height="32" src="http://localhost:3001/api/user/getCaptcha" @click="refreshCaptcha">--js
// 获取验证码cookie
getCookie(cname){var name = cname + "=";var ca = document.cookie.split(';');for(var i=0; i<ca.length; i++){var c = ca[i].trim();if (c.indexOf(name)==0) return c.substring(name.length,c.length);}return "";
},
// 刷新验证码
refreshCaptcha(){this.$refs.captcha.src = "http://localhost:3001/api/user/getCaptcha?d=" + Math.random();
},最后用 填写的验证码进行对比
```
上传歌曲或图片
formidable来处理文件上传信息,用起来方便,很友好,如果你没有接触过文件操作,赶紧收藏起来
封装歌曲方法uploadMusic.js
/**
*
* @author: Mr_Wei
* @version: 1.0.0
* @description: 封装上传音乐方法
* @Date: 2019/10/16 08:35
*
*/ const fs = require('fs');
const path = require('path');
const formidable = require('formidable'); // 文件处理库
const formatTime = require('silly-datetime'); // 格式化数据module.exports = (req, res) => {let form = new formidable.IncomingForm(); //创建上传表单form.encoding = 'utf-8'; // 设置编码格式form.uploadDir = path.join(__dirname, '../static/music'); // 设置上传目录(这个目录必须先创建好)form.keepExtensions = true; // 保留文件后缀名form.maxFieldsSize = 20 * 1024 *1024; // 设置文件大小/* 格式化form数据 */form.parse(req, (err, fields, files) => {let file = files.file;/* 获取异常 */if(err) {return res.status(500).json({'status': 500, result: '服务器内部错误'});}if(file.size > form.maxFieldsSize) {fs.unlink(file.path);return res.status(412).json({'status': 412, result: '音频不能超过20M'});}/* 存储后缀名 */let extName = '';switch (file.type) {case 'audio/mp3':extName = 'mp3';break;}if(extName.length == 0) {fs.unlink(file.path);return res.status(412).json({'status': 412, result: '只支持mp3格式音频'});}/* 拼接新的文件名 */let time = formatTime.format(new Date(), 'YYYYMMDDHHmmss');let num = Math.floor(Math.random() * 8999 + 10000);let songName = `${time}_${num}.${extName}`;let newPath = form.uploadDir + '/' + songName;/* 更改名字和路径 */fs.rename(file.path, newPath, (err) => {if(err) {return res.status(500).json({'status': 500, result: '音频上传失败'});} else {return res.send({'status': 200, 'msg': '音频上传成功', result: {src: songName}});}})})
};
Vue、ElementUI分页使用
关于ElementUI分页详细请见:ElementUI的Paginge
上图
-- html
<el-paginationv-if='paginations.total > 0':page-sizes="paginations.page_sizes":page-size="paginations.page_size":layout="paginations.layout":total="paginations.total":current-page.sync='paginations.page_index'@current-change='handleCurrentChange'@size-change='handleSizeChange'>
</el-pagination>-- js
data(){return{allUsers:[], // 用来存储最终信息, 被显示的dom点调用allTableData:[], // 用户承接分页设置的数据paginations: { // 分页组件信息page_index: 1, // 当前位于哪页total: 0, // 总数page_size: 5, // 1页显示多少条page_sizes: [5, 10, 15, 20], //每页显示多少条layout: "total, sizes, prev, pager, next, jumper" // 翻页属性},}
},
methods:{// 获取当前页handleCurrentChange(page) {let sortnum = this.paginations.page_size * (page - 1);let table = this.allTableData.filter((item, index) => {return index >= sortnum;});// 设置默认分页数据this.getAllUsers = table.filter((item, index) => {return index < this.paginations.page_size;});this.getAllUsers = table.filter((item, index) => {return index < this.paginations.page_size;});},// 切换sizehandleSizeChange(page_size) {this.paginations.page_index = 1;this.paginations.page_size = page_size;this.getAllUsers = this.allTableData.filter((item, index) => {return index < page_size;});},// 总页数setPaginations() {this.paginations.total = this.allTableData.length;this.paginations.page_index = 1;this.paginations.page_size = 5;// 设置默认分页数据this.getAllUsers = this.allTableData.filter((item, index) => {return index < this.paginations.page_size;});},
}
没了吗?对,分页就是这么简单!你学会了吗?有些前端开发的同学总是对分页比较陌生,学会这个,让你不再产生烦恼!
token和自定义验证合法性
jsonwebtoken是对用户信息加密成不可逆向破解的token.关于passport-jwt,是用来对用户请求时所带的token信息进行过期验证,如果超过签证的合法时间,则会请前台发出token失效的信息,提示用户重新获取合法的token信息,否则无法继续请求加密的信息;
用法
- passport-jwt
const key = require("../config/keys").KEYORSECRET;
const JwtStrategy = require('passport-jwt').Strategy,ExtractJwt = require('passport-jwt').ExtractJwt;
var opts = {}
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = key;module.exports = passport => {passport.use(new JwtStrategy(opts, (jwt_payload, done) => {UserInfo.findById(jwt_payload.id).then(user => {if (user) {return done(null, user);} else {return done(null, false);// or you could create a new account}})}));
}// 设置token
// 规则const rule = {id:String(userinfo._id),username:userinfo.username,email:userinfo.email,date:user.date,signdate:userinfo.signdate,signcount:userinfo.signcount,avatar:userinfo.avatar,phone:userinfo.phone
};// 签证加密
// jwt.sign(规则, key(私钥), {配置:比如过期时长}, (err, token){ 响应程序 })
jwt.sign(rule,key,{expiresIn:7200},(err, token) => {if(err) throw err;res.json({"token" : "Bearer " + token})
})自定义验证方法
/**
*
* @author: Mr_Wei
* @version: 1.0.0
* @description: 判断是否过期用户
* @Date: 2019/10/19 12:19
*
*/
const UserOrOrders = require("../dbModel/user");
module.exports = async params => {const flag = await new Promise((resolve) => {if(params){const account = params.account;UserOrOrders.findOne({account}).then(user => {if(user){if(new Date().getTime() > new Date(user.endTime).getTime()){console.log("过期用户");// 处理return resolve(false);}else{console.log("合法用户");return resolve(true);}}else{return resolve(false);}})}else{console.log("不合法用户");return resolve(false);}}) return flag;
}使用:
// 测试 isBadAccount(params)方法
router.post("/test", passport.authenticate("jwt", {session:false}), async (req, res) => {// console.log(req.user)if(await isBadAccount(req.user)){// do somethingres.send("OK");}else{res.status(401).json({status:"401", result:"帐号过期,请联系管理员"})}
})
详细的文档地址:[Passport-Jwt合法验证](passport-jwt),[token加密](jsonwebtoken)
截图
后台管理系统
前台点歌界面
源码在这里
以上代码均已上传 github
1046224544/ktv-select_music-systemgithub.com
联系
如果大家有兴趣,欢迎star. 欢迎大家加入我的前端交流群:866068198 ,一起交流学习前端技术。博主目前一直在自学Node中,技术有限,如果可以,会尽力给大家提供一些帮助,或是一些学习方法.
群二维码
其他
用Node+VueCli+ElemenetUI+MongoDB教你开发综合性教程网站,包括后台管理系统 - 掘金juejin.im
最后
If you have some questions after you see this article, you can contact me or you can find some info by clicking these links.
- [juejin@wsm's juejin](取舍 的个人主页 - 掘金)
- [GitHub@1046224544](1046224544 - Overview)
- [Segmentfault@wsm](https://segmentfault.com/u/xiaolajiao_5d81dbf1f09b2)
如果对你有帮助,请赏个star~
ktv管理系统_7天撸完KTV点歌系统,含后台管理系统(完整版)相关推荐
- 7天撸完KTV点歌系统,含后台管理系统(完整版)
最近手有点痒琢磨着做个啥,朝思暮想还是写个KTV点歌系统,模拟了一下KTV开户的思路,7天累死我了,不过技术点还挺多的,希望你可以看完(〜㉨)〜 用Node(Express)教你写KTV点歌系统,包括 ...
- vuecli 实战商城后台管理系统_前台商城系统及后台管理系统
概述内容 mall项目是一套电商系统,包括前台商城系统及后台管理系统,基于SpringBoot+MyBatis实现. 前台商城系统包含首页门户.商品推荐.商品搜索.商品展示.购物车.订单流程.会员中心 ...
- gulimall(谷粒商城) 是一个综合性的B2C平台,包括前台商城系统以及后台管理系统
介绍: 项目介绍 gulimall(谷粒商城) 项目是一套电商项目,包括前台商城系统以及后台管理系统,基于 SpringCloud + SpringCloudAlibaba + MyBatis-Plu ...
- 课程设计-基于SSM的美容美发造型预约管理系统代码Java理发剪发设计造型系统vue美发店管理系统
课程设计-基于SSM的美容美发造型预约管理系统代码Java理发剪发设计造型系统vue美发店管理系统 注意:该项目只展示部分功能,如需了解,评论区咨询即可. 1.开发环境 开发语言:Java 后台框架: ...
- 基于java springboot的小说阅读微信小程序含后台管理系统源码
系统运行环境 开发工具 eclipse(idea),mysql5.7(大于5.5),navicat,小程序开发工具 硬件要求 windows操作系统 cpu:2.4GHz 内存:4G 硬盘:100G ...
- 后台管理系统怎么实现操作日志原理_springboot角色权限后台管理系统脚手架实战开发教程包含完整源码...
自从猿来入此发布实战开发教程以来,我们截至目前一共发布了22个Java实战项目开发教程,从最基础的Java控制台实战项目到数据库封装教程再到swing的单机项目教程.servlet的web实战教程.s ...
- 前端ui 后台管理系统 简洁_Github上前端不可不知的可视化后台管理系统(1)
AdminLTE 框架简介:AdminLTE是一个完全响应管理模板.基于Bootstrap 4.4框架以及JS / jQuery插件,易于定制模板,且自带多种配色皮肤,可根据需要实时调整.适合多种屏幕 ...
- c# 基于layui的通用后台管理系统_基于spring boot和vuejs的通用后台管理系统脚手架 guns-lite...
Guns-lite 前言 guns-lite是在guns的基础上将数据库层由mybatis替换为spring data jpa的系统. guns-lite是一个基于spring boot的后台管理系统 ...
- JSP学生考勤管理系统考勤管理系统jsp学生迟到早退考勤查询系统(考勤管理系统源码)
常见的Javaweb题材有 理财系统,就业管理系统,汽车租赁,简易网盘,疫情数据查看,在线招标房,屋租赁,教务管理,医院管理,餐厅收银,来访咨询,兼职论坛,桌面聊天室,酒店管理,民宿管理,车位租赁,音 ...
最新文章
- 【POJ】1308 Is It A Tree?((并查集 + set)or (map))
- Azure CosmosDB (3) 选择适当的一致性级别
- __getitem__()
- 软件项目管理0706:工匠精神
- ugly number
- 从零开始实现RPC框架 - RPC原理及实现
- 用WAP手机远程遥控电脑1
- keepalived详解(一)——keepalived理论基础
- CentOS下如何解决认证上网的问题
- RDP报表工具:六大优势铸造核心竞争力
- 那些非常好用的电脑软件
- 优化设计-外点惩罚函数法-MATLAB编程
- #clickid#CID#全新小程序链路CID/clickid解决方案,合规、完美防阿里封禁
- 壳聚糖导管复合辛伐他汀/泊洛沙姆407水凝胶/负载转化生长因子β1温敏性壳聚糖水凝胶的制备
- 使用C++代码解密微信加密数据库信息!
- 笔记-中项/高项学习期间的错题笔记1
- Jasperserver 添加字体方法
- BM发声,孙宇晨入场,国产公链集体进军DeFi
- 艿艿连肝了几个周末,写了一篇贼长的 Spring 响应式 Web 框架 WebFlux!市面第二完整~...
- 年轻人,如何才能抗造之 - 预期管理及心态控制
热门文章
- Linux基础命令--grep/find
- DELL T410服务器U盘安装Centos7
- sqlplus 设置显示格式
- python \uxxxx转中文,Python列表中的字典 \uxxxx转中文,
- [转]WampServer localhost 图标不显示解决办法
- linux下/proc/cpuinfo 文件分析
- 怎样给Spark传递函数—怎样让你的Spark应用更高效更健壮
- 开源加密库和 GnuPG 模块 Libgcrypt 紧急修复严重漏洞
- QuickBI助你成为分析师-仪表板钻取的实现
- Android内存优化11 内存泄漏常见情况2 线程持久化