wbepck+vue环境搭建
webpack+element+vue+express+mangodb+axios增删查(页面适配至移动端320*568)
接上一章博文:webpack+element+vue+express+mangodb+axios显示数据库数据(vue过渡动画)
这次做显示数据库内容,增加插入和删除功能,适配移动端,优化代码结构
demo
下面是demo,自己下着看吧!
demo:https://github.com/jsq-github/department-statistics
目录
代码
与上一篇博文一样或只有小调整的我就不重复贴出来了!!!!!!!!!!!
webpack.prod.js
// eslint-disable-next-line no-undef
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// eslint-disable-next-line no-undef
const merge = require('webpack-merge');
// eslint-disable-next-line no-undef
const webpackBaseConfig = require('./webpack.base');
// eslint-disable-next-line no-undef
const uglify = require('uglifyjs-webpack-plugin');
// eslint-disable-next-line no-undef
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
// eslint-disable-next-line no-undef
const FileManagerPlugin = require('filemanager-webpack-plugin');
// eslint-disable-next-line no-undef
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
// eslint-disable-next-line no-undef
const json = require('../package.json');
// eslint-disable-next-line no-undef
module.exports = merge(webpackBaseConfig,{
module: {
rules: [{
test:/\.css$/,
use:[MiniCssExtractPlugin.loader,'css-loader']
}]
},
plugins: [
new CleanWebpackPlugin(),
new FileManagerPlugin({ //初始化 filemanager-webpack-plugin 插件实例
onEnd: {
// eslint-disable-next-line no-mixed-spaces-and-tabs
copy: [//前后端同时打包,包括依赖,可直接使用 node index直接运行,无需求可删除此copy
{ source: './backend', destination: './staff-stats/backend' },
{ source: './node_modules', destination: './staff-stats/node_modules' },
{ source: './config', destination: './staff-stats/config' }
],
delete: [ //首先需要删除项目根目录下的staff-stats.zip
'./staff-stats-'+json.version+'.zip',
],
archive: [ //然后我们选择staff-stats文件夹将之打包成staff-stats.zip并放在根目录
{source: './staff-stats', destination: './staff-stats-'+json.version+'.zip'},
]
}
}),
new MiniCssExtractPlugin({
filename: 'css/[name].[hash].css',
}),
new OptimizeCSSAssetsPlugin({}),
new uglify()
]
});
App.vue
<template>
<div id="app" class="app">
<div class="heard" id="heard">
<h1>部门统计</h1>
</div>
<div id="main">
<div id="Statistics">
<div id="heard3">
<h4>统计项</h4>
</div>
<el-col :span="12" class="left" style="width: 100%">
<el-menu
class="el-menu-vertical-demo"
background-color="#545c63"
text-color="#fff"
:default-openeds="defaultOpen"
@open="handleOpen"
active-text-color="#ffd04b">
<el-submenu index="1" @click.native="bugs()">
<template slot="title">
<i class="el-icon-info"></i>
<span>BUG排行榜</span>
</template>
<transition
appear
appear-active-class="animated flash"
name="submenu1-transition"
enter-active-class="animated fadeInLeftBig"
>
<el-menu-item-group v-if="showBugs">
<template v-for="user in bugsData">
<el-menu-item align="center" @click="timeOutBugs(user._id)">
<p >{{user._id}} 累计: {{user._sum}}次</p>
</el-menu-item>
</template>
</el-menu-item-group>
</transition>
</el-submenu>
<el-submenu index="2" @click.native="ideas" >
<template slot="title">
<i class="el-icon-info"></i>
<span>IDEAS排行榜</span>
</template>
<transition
appear
appear-active-class="animated flash"
name="submenu2-transition"
enter-active-class="animated fadeInLeftBig"
>
<el-menu-item-group v-if="showIdeas">
<template v-for="user in ideasData">
<el-menu-item align="center" @click.native="timeOutIseas(user._id)">
<p>{{user._id}} 累计: {{user._sum}}次</p>
</el-menu-item>
</template>
</el-menu-item-group>
</transition>
</el-submenu>
</el-menu>
</el-col>
</div>
<div id="table" class="table">
<div id="heard2">
<h4>{{title}}</h4>
</div>
<div id="add1" v-if="add1">
<el-button type="primary" icon="el-icon-plus" round @click="insertBugInfor()">BUG</el-button>
</div>
<div id="add2" v-if="add2">
<el-button type="primary" icon="el-icon-plus" round @click="insertIdeasInfor()">IDEAS</el-button>
</div>
<transition
appear
appear-active-class="animated bounce"
name="table1-transition"
enter-active-class="animated fadeInDown"
>
<el-table :data="tableData.slice((currentPage-1)*pagesize,currentPage*pagesize)"
empty-text="暂时没有数据............."
style="width: 100%"
:cell-style="changeCellStyle"
v-loading="loading"
v-if="showBugs">
<el-table-column min-width="60px" prop="create_date" label="日期" align="center" :formatter="dateFormat"></el-table-column>
<el-table-column min-width="40px" prop="name" label="姓名" align="center"></el-table-column>
<el-table-column min-width="40px" prop="project_name" label="项目" align="center"></el-table-column>
<el-table-column min-width="100px" prop="desc" label="描述"></el-table-column>
<el-table-column
label="操作"
align="center"
min-width="60px">
<template slot-scope="scope">
<el-button type="danger" size="mini" @click="deleteBugInfor(scope.row['desc'])" icon="el-icon-delete"></el-button>
</template>
</el-table-column>
</el-table>
</transition>
<transition
appear
appear-active-class="animated bounce"
name="table2-transition"
enter-active-class="animated fadeInUp"
>
<el-table :data="tableData.slice((currentPage-1)*pagesize,currentPage*pagesize)"
empty-text="暂时没有数据............."
style="width: 100%"
:cell-style="changeCellStyle"
v-if="showIdeas">
<el-table-column min-width="60px" prop="create_date" label="日期" align="center" :formatter="dateFormat"></el-table-column>
<el-table-column min-width="40px" prop="name" label="姓名" align="center"></el-table-column>
<el-table-column min-width="40px" prop="project_name" label="项目" align="center"></el-table-column>
<el-table-column min-width="100px" prop="desc" label="描述"></el-table-column>
<el-table-column
label="操作"
align="center"
min-width="60px">
<template slot-scope="scope">
<el-button type="danger" size="mini" @click="deleteIdeasInfor(scope.row['desc'])" icon="el-icon-delete"></el-button>
</template>
</el-table-column>
</el-table>
</transition>
<div id="pagination1" class="pagination1" v-if="fenye1">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[5, 10, 20, 40]"
:page-size="pagesize"
layout="total, sizes, prev, pager, next"
:total="tableData.length"
:pager-count="5">
</el-pagination>
</div>
<div id="pagination2" class="pagination2" v-if="fenye2">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[5, 10, 20, 40]"
:page-size="10"
layout="total, sizes, prev, next"
:total="tableData.length">
</el-pagination>
</div>
</div>
<!--添加数据-->
<el-dialog title="添加数据" :visible.sync="insertFormVisible" class="addArea" modal custom-class="insertFormArea" @close="closeInsert('insertForm')">
<el-form :model="insertForm" class="insertForm" :rules="rules" status-icon ref="insertForm">
<el-form-item label="姓名:" prop="name">
<el-input v-model="insertForm.name" auto-complete="off" placeholder="请输入姓名"></el-input>
</el-form-item>
<el-form-item label="项目:" prop="project_name">
<el-input v-model="insertForm.project_name" auto-complete="off" placeholder="请输入项目名"></el-input>
</el-form-item>
<el-form-item label="描述:" prop="desc">
<el-input v-model="insertForm.desc" auto-complete="off" placeholder="请输入描述"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="insertFormVisible = false">取 消</el-button>
<el-button type="primary" @click="insertSure('insertForm')">提交</el-button>
</div>
</el-dialog>
</div>
</div>
</template>
<script>
import axios from 'axios';
import moment from 'moment';
export default {
name: 'App2',
data () {
return {
message: 'index.html',
tableData: [],
bugsData: [],
title: '详情',
ideasData: [],
loading: true,
showBugs: true,
showIdeas: false,
// eslint-disable-next-line vue/no-reserved-keys
_id: '',
url: 'bugs',
flag: 1,
add1: true,
add2: false,
defaultOpen: ['1'],
currentPage: 1, //默认显示页面为1
pagesize: 10, //每页的数据条数
insertFormVisible: false,
insertForm: {
project_name: '',
desc: '',
name: '',
screenWidth: window.innerHeight,
},
fenye1: true,
fenye2: false,
screenWidth: 0,
rules: {
name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
project_name: [{ required: true, message: '请输入项目名', trigger: 'blur' }],
desc: [{ required: true, message: '请输入描述', trigger: 'blur' }]
}
};
},
methods: {
dateFormat:function(row, column) {
const date = row[column.property];
if (date == undefined) {
return '';
}
return moment(date).format('YYYY-MM-DD HH:mm:ss');
},
handleSizeChange: function(size) {
this.pagesize = size;
},
//点击第几页
handleCurrentChange: function(currentPage) {
this.currentPage = currentPage;
},
changeCellStyle({rowIndex}) {
//第八列添加 red 类
if(rowIndex%2 === 1){
return 'backgroundColor: #FFFFEE';
}
},
ideas: function () {
this.flag=2;
this.title = 'IDEAS详情';
axios.get('http://localhost:3000/api/ideas/find').then((res)=>{
this.tableData = (res.data);
console.log(this.tableData);
}).catch((err)=>{
console.log(err);
});
this.showBugs = false;
this.showIdeas = true;
this.loading = false;
this.add2 = true;
this.add1 = false;
this.ideasNum();
},
bugs: function () {
this.flag=1;
this.title = 'BUG详情';
axios.get('http://localhost:3000/api/bugs/find').then((res)=>{
this.tableData = (res.data);
console.log(this.tableData);
console.log();
}).catch((err)=>{
console.log(err);
});
this.showBugs = true;
this.showIdeas = false;
this.loading =false;
this.add1 = true;
this.add2 = false;
this.bugNum();
},
bugNum: function () {
axios.get('http://localhost:3000/api/bugs/find_group').then((res)=>{
this.bugsData = (res.data);
console.log(this.bugsData);
}).catch((err)=>{
console.log(err);
});
},
ideasNum: function () {
axios.get('http://localhost:3000/api/ideas/find_group').then((res)=>{
this.ideasData = (res.data);
console.log(this.ideasData);
}).catch((err)=>{
console.log(err);
});
},
//展开当前一级菜单,关闭其他的菜单
handleOpen: function(key) {
//当前打开的sub-menu的 key 数组
this.defaultOpen = [key];
console.log(this.defaultOpen);
},
selfBugsInfor: function (name) {
let params = {
name: name,
};
this.flag = 2;
this.title = name+'的BUG详情';
axios.post('http://localhost:3000/api/bugs/findSelf', params).then((res)=>{
this.tableData = (res.data);
console.log(res.data);
}).catch((err)=>{
console.log(err);
});
},
selfIdeasInfor: function (name) {
let params = {
name: name,
};
this.flag = 2;
this.title = name+'的IDEAS详情';
axios.post('http://localhost:3000/api/ideas/findSelf', params).then((res)=>{
this.tableData = (res.data);
console.log(res.data);
}).catch((err)=>{
console.log(err);
});
},
timeOutBugs: function (name) {
const that = this;
setTimeout(() =>{that.selfBugsInfor(name);},30);
},
timeOutIseas: function (name) {
const that = this;
setTimeout(() =>{that.selfIdeasInfor(name);},30);
},
insertBugInfor: function () {
this.insertFormVisible = true;
},
insertIdeasInfor: function () {
// eslint-disable-next-line no-mixed-spaces-and-tabs
this.insertFormVisible = true;
},
deleteBugInfor: function (desc) {
this.$confirm('此操作永久删除该数据,是否继续?', '提示',{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let params = {
desc: desc,
};
this.showBugs = true;
this.showIdeas = false;
this.loading = false;
this.currentPage = 1;
axios.post('http://localhost:3000/api/bugs/delete', params).then((res) => {
if (res.data) {
alert('删除成功!');
}
this.bugs();
this.bugNum();
}).catch((err) => {
console.log(err);
alert('删除失败!');
});
});
},
deleteIdeasInfor: function (desc) {
this.$confirm('此操作永久删除该数据,是否继续?', '提示',{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let params = {
desc: desc,
};
this.showBugs = false;
this.showIdeas = true;
this.loading = false;
this.currentPage = 1;
axios.post('http://localhost:3000/api/ideas/delete', params).then((res) => {
if (res.data) {
alert('删除成功!');
}
this.ideas();
this.ideasNum();
}).catch((err) => {
console.log(err);
alert('删除失败!');
});
});
},
insertSure: function () {
console.log(this.insertForm);
if(this.add1) {
this.url = 'bugs';
}
if(this.add2) {
this.url = 'ideas';
}
if(this.insertForm === '' || this.insertForm.project_name === '' || this.insertForm.desc === ''){
alert('添加失败!输入不能为空!');
return;
}
axios.post('http://localhost:3000/api/'+this.url+'/insert',this.insertForm).then((res)=>{
if(res.data){
alert('添加成功!');
}
this.insertFormVisible = false;
if(this.add1) {
this.bugs();
this.bugNum();
}
if(this.add2) {
this.ideas();
this.ideasNum();
}
this.insertForm.desc = '';
this.insertForm.name = '';
this.insertForm.project_name = '';
}).catch((err)=>{
console.log(err);
alert('添加失败!');
});
},
closeInsert: function(formName) {
this.$refs[formName].resetFields();
},
},
mounted () {
const that = this;
that.screenWidth = `${document.documentElement.clientWidth}`;
if(that.screenWidth >= 1036 ) {
that.fenye1 = true;
that.fenye2 = false;
console.log(that.fenye2);
}else {
that.fenye1 = false;
that.fenye2 = true;
}
window.onresize = function temp() {
that.screenWidth = `${document.documentElement.clientWidth}`;
if(that.screenWidth >= 1036 ) {
that.fenye1 = true;
that.fenye2 = false;
console.log(that.fenye2);
}else {
that.fenye1 = false;
that.fenye2 = true;
}
};
axios.get('http://localhost:3000/api/bugs/find').then((res)=>{
this.tableData = (res.data);
this.loading = false;
this.title = 'BUG详情';
console.log(this.tableData);
}).catch((err)=>{
console.log(err);
});
axios.get('http://localhost:3000/api/bugs/find_group').then((res)=>{
this.bugsData = (res.data);
console.log(this.bugsData);
}).catch((err)=>{
console.log(err);
});
axios.get('http://localhost:3000/api/ideas/find_group').then((res)=>{
this.ideasData = (res.data);
console.log(this.ideasData);
}).catch((err)=>{
console.log(err);
});
},
};
</script>
<style>
@media screen and (min-width:1050px) {
#heard {
width: 100%;
height: 80px;
margin: 0px auto;
}
#main {
width: 100%;
margin: 10px auto;
height: 780px;
}
#Statistics {
width: 22%;
height: 780px;
float: left;
margin-left:30px;
}
#table {
width: 65%;
height: 780px;
float: right;
margin-right:30px;
}
.pagination1 {
float: right;
}
.pagination2 {
float: right;
}
#heard2{
float:left;
}
#add1{
float: right;
margin-top: 20px;
}
#add2{
float: right;
margin-top: 20px;
}
}
@media screen and (max-width:1050px) {
#heard {
width: 100%;
height: 9%;
}
#main {
width: 100%;
height: 200%;
}
#Statistics {
width: 100%;
height: 100%;
float: top;
}
#table {
width: 100%;
height: 100%;
float: bottom;
}
.pagination1 {
float: right;
}
.pagination2 {
float: right;
}
#heard2 {
float:left;
}
#add1 {
float: right;
margin-top: 10px;
}
#add2 {
float: right;
margin-top: 10px;
}
}
</style>
api.js
// eslint-disable-next-line no-undef
const bugs = require('../model/bugs').bugs;
// eslint-disable-next-line no-undef
const ideas = require('../model/ideas').ideas;
// eslint-disable-next-line no-undef
const express = require('express');
const router = express.Router();
// eslint-disable-next-line no-undef
const send = require('../../config/send');
// eslint-disable-next-line no-undef
const mongoose = require('mongoose');
const date = Date.now();
router.get('/api/bugs/find', (function (req, res) {
bugs.aggregate([{$sort: {create_date: -1}}] , function (err, results) {
send(err,res,results);
});
}));
router.post('/api/bugs/findSelf', (function (req, res) {
bugs.aggregate([{$match: {'name': req.body.name}},{$sort: {create_date: -1}}] , function (err, results) {
send(err,res,results);
});
}));
router.get('/api/bugs/find_group', (function (req, res) {
bugs.aggregate([{$group : {_id: '$name', _sum: {$sum : 1}}},{$sort: {_sum:-1}}] , function (err, results) {
send(err,res,results);
});
}));
router.post('/api/bugs/insert', (function (req, res) {
bugs.create({'_id': mongoose.Types.ObjectId(), 'desc': req.body.desc, 'name': req.body.name, 'project_name': req.body.project_name, 'create_date': date}, function (err,results) {
send(err,res,results);
});
}));
router.post('/api/bugs/delete', (function (req, res) {
bugs.deleteOne({'desc': req.body.desc}, function (err,results) {
send(err,res,results);
});
}));
router.get('/api/ideas/find', (function (req, res) {
ideas.aggregate([{$sort: {create_date: -1}}] , function (err, results) {
send(err,res,results);
});
}));
router.post('/api/ideas/findSelf', (function (req, res) {
ideas.aggregate([{$match: {'name': req.body.name}},{$sort: {create_date: -1}}] , function (err, results) {
send(err,res,results);
});
}));
router.get('/api/ideas/find_group', (function (req, res) {
ideas.aggregate([{$group : {_id: '$name', _sum: {$sum : 1}}},{$sort: {_sum:-1}}] , function (err, results) {
send(err,res,results);
});
}));
router.post('/api/ideas/insert', (function (req, res) {
ideas.create({'_id': mongoose.Types.ObjectId(), 'desc': req.body.desc, 'name': req.body.name, 'project_name': req.body.project_name, 'create_date': date}, function (err,results) {
send(err,res,results);
});
}));
router.post('/api/ideas/delete', (function (req, res) {
ideas.deleteOne({'desc': req.body.desc}, function (err,results) {
send(err,res,results);
});
}));
// eslint-disable-next-line no-undef
module.exports = router;
db.js
// eslint-disable-next-line no-undef
const mongoose = require('mongoose');
function conn() {
mongoose.connect('mongodb://xxxx:cE8ab5d9sdsdfefdfwefR3yRY94U@xxxxx-dev.xxxxxxx.com:000008/xxxxxxx', {useNewUrlParser:true});
const message = mongoose.connection;
message.once('error', () => console.log('Mongo connection error'));
message.once('open', () => console.log('Mongo connection successed'));
}
// eslint-disable-next-line no-undef
module.exports = conn;
_index.js
扫描目录下的model,一个model对应数据库一个表
'use strict';
// eslint-disable-next-line no-undef
const requireDirectory = require('require-directory');
// eslint-disable-next-line no-undef
module.exports = requireDirectory(module, './');
bugs.js
// eslint-disable-next-line no-undef
const mongoose = require('mongoose');
// eslint-disable-next-line no-undef
const connect = require('../../config/db');
connect();
const model = mongoose.Schema({
_id: String,
name: String,
desc: String,
project_name: String,
create_date: Number
},{versionKey: false});
const Models = {
bugs: mongoose.model('bugs', model),
};
// eslint-disable-next-line no-undef
module.exports = Models;
ideas.js
// eslint-disable-next-line no-undef
const mongoose = require('mongoose');
// eslint-disable-next-line no-undef
const connect = require('../../config/db');
connect();
const model = mongoose.Schema({
_id: String,
name: String,
desc: String,
project_name: String,
create_date: Number
},{versionKey: false});
const Models = {
ideas: mongoose.model('ideas', model),
};
// eslint-disable-next-line no-undef
module.exports = Models;
send.js
function send(err,res,results) {
if(err){
console.log('Error:' + err);
res.send(err);
}else{
res.header('Access-Control-Allow-Origin', '*');
res.send(results);
}
}
// eslint-disable-next-line no-undef
module.exports = send;
运行结果
网页正常比例
移动端,适配至iphone5(320*568)
插入功能
删除功能