后端人员开发前端vue。
git地址:https://github.com/1065744299/vue-elment-ui
演示地址:https://1065744299.github.io/
csdn下载源码地址:https://download.youkuaiyun.com/download/qq_25451199/11256228
这个demo主要用到vue、vueRouter、vueX、element UI、echarts等技术。主要以展示怎么使用为主。主要的功能有登录、路由、store、报表、导出等。
这里用vue的多页面功能,为了组件的重复使用。
开始介绍代码:
为了打包的时候直打包一个页面,这里对vue.config.js做了修改;代码如下:
var projectname = process.argv[5]
var glob = require('glob')
function getEntry () {
var entries = {}
if (process.env.NODE_ENV === 'production') {
entries = {
index: {
// page的入口
entry: 'src/modules/' + projectname + '/main.js',
// 模板来源
template: 'public/index.html',
// 在 dist/index.html 的输出
filename: 'index.html',
title: projectname,
chunks: ['chunk-vendors', 'chunk-common', 'index']
}
}
} else {
var items = glob.sync('./src/modules/*/*.js')
for (var i in items) {
var filepath = items[i]
var fileList = filepath.split('/')
var fileName = fileList[fileList.length - 2]
entries[fileName] = {
entry: `src/modules/${fileName}/main.js`,
// 模板来源
template: `public/index.html`,
// 在 dist/index.html 的输出
filename: `${fileName}.html`,
// 提取出来的通用 chunk 和 vendor chunk。
chunks: ['chunk-vendors', 'chunk-common', fileName]
}
}
}
return entries
}
var pages = getEntry()
// vue.config.js
module.exports = {
// 基本路径
publicPath: '/',
// 输出文件目录
// outputDir: 'dist',
// webpack-dev-server 相关配置
devServer: {
port: 8888
},
// 生产禁止显示源代码
productionSourceMap: false,
// 输出文件目录
outputDir: 'dist/' + projectname,
pages: pages
}
下面开始搭建一个简单的demo。
主要有几个基础的组件。
先了解下项目结构:
这里主要说组件的内容。
- Home.vue
主页组件
<template>
<el-container>
<el-header>
<Head :isCollapse='isCollapse' @changeCollapse="changeCollapsed" :sysName='sysName' :userInfo='homeUserInfo' @logoutHandle='logoutHandle'></Head>
</el-header>
<el-container>
<el-aside :class="isCollapse?'menu-collapsed':'menu-expanded'">
<Menu :isCollapse='isCollapse' :defaultActive="defaultActive" :menuJson='menuJson' @selectedTab="selectedTab(arguments)"/>
</el-aside>
<el-main>
<div class="my-main">
<Main :editableTabsValue="editableTabsValue" ref="myMain" @selectedTab="mainSelectedTab(arguments)"/>
</div>
</el-main>
</el-container>
</el-container>
</template>
<script>
import Menu from '@/components/Menu.vue'
import Head from '@/components/Head.vue'
import Main from '@/components/Main.vue'
export default {
name: 'app',
props: ['sysName', 'userInfo', 'menuJson'],
components: {
Menu,
Head,
Main
},
data () {
return {
// 菜单是否折叠
'isCollapse': false,
// 主展示区默认选项卡
'editableTabsValue': '首页',
// 菜单默认选中
'defaultActive': '/main/home'
}
},
computed: {
'homeUserInfo': function () {
return this.userInfo
}
},
methods: {
changeCollapsed: function () {
this.isCollapse = !this.isCollapse
},
selectedTab: function (args) {
this.editableTabsValue = args[0]
this.defaultActive = args[1]
this.$refs.myMain.addTab(this.editableTabsValue, this.defaultActive)
},
mainSelectedTab: function (args) {
this.editableTabsValue = args[0]
this.defaultActive = args[1]
},
myRoute: function (index) {
this.$router.push({ 'path': index })
},
logoutHandle: function () {
this.$emit('logoutHandle')
}
},
created: function () {
this.myRoute(this.defaultActive)
}
}
</script>
<style>
html,body,#app,.el-container {
height: 100%;
}
.el-header {
color: #333;
line-height: 60px;
padding: 0 0px;
}
.el-aside {
background-color: #eef1f6;
color: #333;
line-height: 200px;
}
.el-main {
color: #333;
padding: 0 0 0 0px;
width: 100%;
}
.menu-collapsed{
flex:0 0 65px;
width: 65px;
}
.menu-expanded{
flex:0 0 201px;
width: 201px;
}
body{
margin: 0px;
}
main {
height: 100%;
overflow-y: auto;
}
</style>
- Head.vue
头部组件
<template>
<el-col :span="24" class="header">
<el-col :span="10" class="logo " :class="isCollapse?'logo-collapse-width':'logo-width'">
{{isCollapse?'':sysName}}
<img src="../assets/w.jpg" width="66px" height="100%" v-show="isCollapse"/>
</el-col>
<el-col :span="10">
<div class="tools">
<i :class="isCollapse?'el-icon-s-unfold':'el-icon-s-fold'" @click="pchangeCollapse"></i>
</div>
</el-col>
<el-col :span="4" class="userinfo">
<el-dropdown trigger="hover">
<span class="el-dropdown-link userinfo-inner"><img :src="img"/>{{name}}</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>我的消息</el-dropdown-item>
<el-dropdown-item>设置</el-dropdown-item>
<el-dropdown-item @click.native="logoutHandle">退出登录</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-col>
</el-col>
</template>
<script>
let userInfo = {
name: '苏三杰',
img: 'https://raw.githubusercontent.com/taylorchen709/markdown-images/master/vueadmin/user.png'
}
export default {
props: {
'isCollapse': {
type: Boolean,
default: true
},
'userInfo': {
type: Object,
default: () => userInfo
},
'sysName': {
type: String,
default: 'WEBDEMO'
}
},
data () {
return {}
},
computed: {
'name': function () {
return this.userInfo.name
},
'img': function () {
return this.userInfo.img
}
},
methods: {
pchangeCollapse: function () {
this.$emit('changeCollapse')
},
logoutHandle: function () {
this.$confirm('确定要退出吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
// this.$message({
// type: 'success',
// message: '删除成功!'
// })
this.$emit('logoutHandle')
}).catch(() => {
this.$message({
type: 'info',
message: '已取消退出'
})
})
}
}
}
</script>
<style scoped>
.header {
height: 60px;
line-height: 60px;
background: #67C23A;
color:#fff
}
.userinfo {
height: 60px;
line-height: 60px;
text-align: right;
padding-right: 35px;
float: right;
}
.userinfo-inner {
height: 60px;
line-height: 60px;
cursor: pointer;
color:#fff;
}
.userinfo-inner>img {
cursor: pointer;
color:#fff;
width: 40px;
height: 40px;
border-radius: 20px;
margin: 10px 0px 10px 10px;
float: right;
}
.logo {
height:60px;
font-size: 22px;
border-color: rgba(238,241,146,0.3);
border-right-width: 1px;
border-right-style: solid;
}
.txt {
color:#fff;
}
.logo-width{
width:202px;
padding-left:20px;
padding-right:20px;
}
.logo-collapse-width{
width:65px;
padding-left:0px;
padding-right:0px;
}
.tools{
padding: 0px 23px;
width:14px;
height: 60px;
line-height: 60px;
cursor: pointer;
}
</style>
- Main.vue
主展示区组件
<template>
<el-tabs v-model="myEditableTabsValue" type="card" closable @tab-remove="removeTab" @tab-click="goRoute">
<el-tab-pane
v-for="(item) in editableTabs"
:key="item.name"
:label="item.title"
:name="item.name"
:myindex="item.index"
>
<div class="mymain">
<router-view/>
</div>
</el-tab-pane>
</el-tabs>
</template>
<script>
export default {
props: ['editableTabsValue'],
data () {
return {
editableTabs: [{
title: '首页',
name: '首页',
index: '/main/home'
}],
myEditableTabsValue: this.editableTabsValue
}
},
methods: {
addTab (name, index) {
for (var t in this.editableTabs) {
if (this.editableTabs[t].name === name) {
this.myEditableTabsValue = name
return
}
}
this.editableTabs.push({
title: name,
name: name,
index: index
})
this.myEditableTabsValue = name
},
removeTab (targetName) {
let tabs = this.editableTabs
let activeName = this.myEditableTabsValue
// let activeName = ''
let _index = ''
if (activeName === targetName) {
tabs.forEach((tab, index) => {
if (tab.name === targetName) {
let nextTab = tabs[index + 1] || tabs[index - 1]
if (nextTab) {
activeName = nextTab.name
_index = nextTab.index
}
}
})
}
this.$router.push({ 'path': _index })
this.$emit('selectedTab', activeName, _index)
this.myEditableTabsValue = activeName
this.editableTabs = tabs.filter(tab => tab.name !== targetName)
},
goRoute (args) {
let tabs = this.editableTabs
let _thisTab = tabs.filter(tab => tab.name === args.name)[0]
this.$router.push({ 'path': _thisTab.index })
this.$emit('selectedTab', _thisTab.name, _thisTab.index)
// this.$emit('myRoute', _thisTab.index)
}
}
}
</script>
<style scoped>
.mymain {
padding: 0 5px
}
</style>
- Menu.vue
菜单组件
<template>
<div>
<el-menu
:default-active="defaultActive"
class="el-menu-vertical-demo"
@open="handleOpen"
@close="handleClose"
:collapse="isCollapse"
background-color="#eef1f6"
active-text-color="#20a0ff"
:collapse-transition="false"
text-color="#48576a"
:router="true"
>
<template v-for="m in menus">
<el-submenu v-if="m.type=='subMenu'" :index="m.id" :key="m.id">
<template slot="title">
<i :class="m.icon"></i>
<span slot="title">{{m.name}}</span>
</template>
<el-menu-item v-for="mi in m.submenus" :key="mi.id" :index="mi.url" :route="{path: mi.url}" @click.native="selected(mi.name, mi.url)">
{{mi.name}}
</el-menu-item>
</el-submenu>
<el-menu-item v-if="m.type=='menu-item'" :index="m.url" :key="m.id" :route="{path: m.url}" @click.native="selected(m.name, m.url)">
<i :class="m.icon"></i>
<span slot="title">
{{m.name}}
</span>
</el-menu-item>
</template>
</el-menu>
</div>
</template>
<script>
let menuJson = [
{
id: '1',
name: '首页',
type: 'menu-item',
url: '/',
icon: 'el-icon-star-off',
submenus: []
},
{
id: '2',
name: 'TableS',
type: 'subMenu',
url: '',
icon: 'el-icon-s-grid',
submenus: [
{
id: '3',
name: '动态table',
type: 'subMenu',
url: '/about',
icon: ''
},
{
id: '4',
name: '拖拽table',
type: 'subMenu',
url: '/about1',
icon: ''
},
{
id: '5',
name: '综合table',
type: 'subMenu',
url: '/about2',
icon: ''
}
]
},
{
id: '6',
name: '列表demo',
type: 'subMenu',
url: '',
icon: 'el-icon-user',
submenus: [
{
id: '7',
name: '用户列表',
type: 'subMenu',
url: '/user',
icon: ''
}
]
}
]
export default {
// props: ['isCollapse', 'defaultActive', 'menuJson'],
props: {
'isCollapse': {
type: Boolean,
default: true
},
'defaultActive': {
type: String,
default: '首页'
},
'menuJson': {
type: Array,
default: () => menuJson
}
},
data () {
return {
menus: this.menuJson
}
},
methods: {
handleOpen (key, keyPath) {
console.log(key, keyPath)
},
handleClose (key, keyPath) {
console.log(key, keyPath)
},
selected (name, index) {
this.$emit('selectedTab', name, index)
}
}
}
</script>
<style>
.el-menu-vertical-demo:not(.el-menu--collapse) {
width: 200px;
}
.el-menu {
border-right: solid 0px #e6e6e6;
}
</style>
- Table.vue
列表组件
<template>
<div>
<el-table :data="datas" v-bind="tableAttrs" v-on="tableEvents" :cell-style="{padding:0}" style="width: 100%;" :header-cell-style="{background:'#eef1f6',color:'#606266'}">
<el-table-column v-for="(item, index) in columns" :key="index" v-bind="item"></el-table-column>
<slot></slot>
</el-table>
</div>
</template>
<script>
export default {
props: ['datas', 'tableAttrs', 'tableEvents', 'columns'],
methods: {
}
}
</script>
<style>
.el-table__row>td {
height: 30px
}
</style>
- Page.vue
页码组件
<template>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[20, 40, 80, 100]"
:page-size="20"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
>
</el-pagination>
</template>
<script>
export default {
props: ['currentPage', 'total'],
data () {
return {
}
},
methods: {
handleSizeChange (val) {
this.$emit('handleSizeChange', val)
},
handleCurrentChange (val) {
this.$emit('handleCurrentChange', val)
}
}
}
</script>
<style>
</style>
- CommonPage.vue
常用主页面组件(这个很重要,为以后直接生成页面做准备)
<template>
<div>
<el-row :gutter="10">
<el-col :span="24" v-if="formEntity">
<div class="bg-purple-dark">
<el-form :inline="true" :model="formInline">
<template v-for="(item, index) in formEntity">
<template v-if="item.template === 'input'">
<el-form-item :label="item.label" :key="index">
<el-input v-model="formInline[item.name]" size="small" v-bind="item"></el-input>
</el-form-item>
</template>
<template v-if="item.template === 'date'">
<el-form-item :label="item.label" :key="index">
<el-date-picker v-model="formInline[item.name]" size="small" v-bind="item"></el-date-picker>
</el-form-item>
</template>
<template v-if="item.template === 'select'">
<el-form-item :label="item.label" :key="index">
<el-select v-model="formInline[item.name]" size="small" v-bind="item">
<el-option v-for="(option, index) in item.options" :key="index" :label="option.label" :value="option.value"></el-option>
</el-select>
</el-form-item>
</template>
</template>
<el-form-item>
<el-button type="primary" size="small" @click="queryF">查询</el-button>
</el-form-item>
</el-form>
</div>
</el-col>
</el-row>
<el-row v-if="buttons && buttons.length > 0">
<el-button plain size="small" v-for="(item , index) in buttons" :key="index" v-bind="item" @click="buttonClick(item.callback)">{{item.label}}</el-button>
</el-row>
<el-row v-if="tableEntity">
<Table v-bind="tableEntity.options">
<el-table-column v-if="tableEntity.options.operationColumn && tableEntity.options.operationColumn.length > 0" label="操作">
<template scope="scope">
<el-button plain v-for="(item, index) in tableEntity.options.operationColumn" :key="index" size="mini" v-bind="item" @click="tableoperationcallback(scope.$index, scope.row,item.callback)">{{item.label}}</el-button>
</template>
</el-table-column>
</Table>
</el-row>
<el-row v-if="tableEntity.page" style="background: #EEF1F6;">
<div class="bg-purple-dark">
<Page
:currentPage="tableEntity.page.currentPage"
:total="tableEntity.page.total"
@handleSizeChange="handleSizeChange"
@handleCurrentChange="handleCurrentChange"
/>
</div>
</el-row>
</div>
</template>
<script>
import Table from '@/components/Table.vue'
import Page from '@/components/Page.vue'
export default {
props: {
// 查询实体
formEntity: {
type: Array
},
queryFunction: {
type: Function
},
tableEntity: {
type: Object
},
buttons: {
type: Array
}
},
components: {
Table,
Page
},
data () {
return {
formInline: {}
}
},
methods: {
// 查询方法
queryF () {
if (this.queryFunction) {
this.queryFunction(this.formInline)
}
},
// 列表操作事件
tableoperationcallback: function (index, row, callback) {
if (callback) {
callback(index, row)
}
},
// 页面列表记录数改表
handleSizeChange (val) {
if (this.tableEntity.page && this.tableEntity.page.handleSizeChange) {
this.tableEntity.page.handleSizeChange(val)
}
},
// 点击其他页面
handleCurrentChange (val) {
if (this.tableEntity.page && this.tableEntity.page.handleCurrentChange) {
this.tableEntity.page.handleCurrentChange(val)
}
},
// 按钮点击事件
buttonClick (fun) {
if (fun) {
fun()
}
}
}
}
</script>
<style scoped>
.bg-purple-dark {
border-radius: 4px;
background: #EEF1F6;
padding: 5px;
}
.el-form-item {
margin: 5px;
}
.el-row {
margin-bottom: 5px;
}
.el-form-item__label {
min-width: 70px;
}
</style>
上面就把主要的组件写完了,下面就是一个应用。
这个应用使用多级路由和vuex。
- App.vue
<template>
<div id="app">
<router-view/>
</div>
</template>
<script>
import axios from './utils/http'
export default {
components: {
// Home
},
data () {
return {
// userInfo: userInfo,
// sysName: sysName,
// menuJson: menuJson
}
},
methods: {
logoutHandle: function () {
// TODO
console.log('退出')
},
testApi: function () {
// http://10.98.3.27:8080/app/mock/data/139
axios
.get('http://10.98.3.27:8080/app/mock/data/139')
.then(response => {
console.info(response)
console.info(response.data)
})
.catch(error => {
console.log(error)
})
.finally(() => console.log('finally'))
}
},
created: function () {
// this.testApi()
this.$router.push({ 'path': '/main/home' })
}
}
</script>
<style>
html, body, #app{
width: 100%;
}
</style>
- main.js
import Vue from 'vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import App from './App.vue'
import router from './router'
import store from './store'
// import axios from 'axios'
// import VueAxios from 'vue-axios'
// import http from './utils/http'
// import VueAxios from 'vue-axios'
// Vue.use(VueAxios, http)
Vue.use(ElementUI)
// Vue.use(http)
Vue.config.productionTip = false
// 做拦截
router.beforeEach((to, from, next) => {
// 判断该路由是否需要登录权限
if (to.path !== '/login') {
// 判断当前的user_id是否存在 ; 登录存入的user_id
if (store.state.userInfo.name) {
next()
} else {
next({
path: '/login',
// 将要跳转路由的path作为参数,传递到登录页面
query: { redirect: to.fullPath }
})
}
} else {
next()
}
})
new Vue({
router,
store,
// http,
render: h => h(App)
}).$mount('#app')
- router.js
import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'
Vue.use(Router)
export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
// {
// path: '/home',
// name: 'home',
// component: Home
// },
// {
// path: '/about',
// name: 'about',
// // route level code-splitting
// // this generates a separate chunk (about.[hash].js) for this route
// // which is lazy-loaded when the route is visited.
// component: () => import(/* webpackChunkName: "about" */ './views/About.vue')
// },
// {
// path: '/user',
// name: 'user',
// component: () => import('./views/User.vue')
// },
{
path: '/login',
name: 'login',
component: () => import('./views/Login.vue')
},
{
path: '/main',
name: 'main',
component: () => import('./views/MyMain.vue'),
children: [
{
path: 'home',
name: 'home',
component: Home
},
{
path: 'about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ './views/About.vue')
},
{
path: 'user',
name: 'user',
component: () => import('./views/User.vue')
},
{
path: 'order',
name: 'order',
component: () => import('./views/Order.vue')
},
{
path: 'echarts',
name: 'echarts',
component: () => import('./views/Echarts.vue')
},
{
path: 'export',
name: 'export',
component: () => import('./views/Export.vue')
},
{
path: 'about1',
name: 'about1'
},
{
path: 'about2',
name: 'about2'
},
{
path: 'ioc',
name: 'ioc'
}
]
}
]
})
- store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
userInfo: {
// name: 'Vuex',
// img: 'https://raw.githubusercontent.com/taylorchen709/markdown-images/master/vueadmin/user.png'
}
},
mutations: {
login (state, user) {
state.userInfo = user
}
},
actions: {
}
})
- http.js
这里使用axios和后台交互,具体业务请自己完善。这里没有具体的使用
import axios from 'axios'
// import {Loading, Message} from 'element-ui'
// import store from '../store'
// import VueAxios from 'vue-axios'
// import Vue from 'vue'
// Vue.use(VueAxios, axios)
/**
* 提示函数
* 禁止点击蒙层、显示一秒后关闭
*/
const tip = msg => {
// Message({
// message: msg,
// duration: 1000,
// forbidClick: true
// })
}
/**
* 跳转登录页
* 携带当前页面路由,以期在登录页面完成登录后返回当前页面
*/
const toLogin = () => {
// router.replace({
// path: '/login',
// query: {
// redirect: router.currentRoute.fullPath
// }
// })
}
/**
* 请求失败后的错误统一处理
* @param {Number} status 请求失败的状态码
*/
const errorHandle = (status, other) => {
// 状态码判断
switch (status) {
// 401: 未登录状态,跳转登录页
case 401:
toLogin()
break
// 403 token过期
// 清除token并跳转登录页
case 403:
tip('登录过期,请重新登录')
localStorage.removeItem('token')
// store.commit('loginSuccess', null)
setTimeout(() => {
toLogin()
}, 1000)
break
// 404请求不存在
case 404:
tip('请求的资源不存在')
break
default:
console.log(other)
}
}
// 创建axios实例
var instance = axios.create({ timeout: 1000 * 12 })
// 设置post请求头
instance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'
/**
* 请求拦截器
* 每次请求前,如果存在token则在请求头中携带token
*/
instance.interceptors.request.use(
config => {
// 登录流程控制中,根据本地是否存在token判断用户的登录情况
// 但是即使token存在,也有可能token是过期的,所以在每次的请求头中携带token
// 后台根据携带的token判断用户的登录情况,并返回给我们对应的状态码
// 而后我们可以在响应拦截器中,根据状态码进行一些统一的操作。
// const token = store.state.token
// token && (config.headers.Authorization = token)
console.log('interceptors')
return config
},
error => Promise.error(error))
// 响应拦截器
instance.interceptors.response.use(
// 请求成功
res => res.status === 200 ? Promise.resolve(res) : Promise.reject(res),
// 请求失败
error => {
const { response } = error
if (response) {
// 请求已发出,但是不在2xx的范围
errorHandle(response.status, response.data.message)
return Promise.reject(response)
} else {
// 处理断网的情况
// eg:请求超时或断网时,更新state的network状态
// network状态在app.vue中控制着一个全局的断网提示组件的显示隐藏
// 关于断网组件中的刷新重新获取数据,会在断网组件中说明
// store.commit('changeNetwork', false)
}
})
export default instance
- About.vue
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
</template>
- Echarts.vue
<template>
<div>
<el-row :gutter="20" class="echarts-row">
<el-col :span="6"><div id = "echartss" class="echarts-div" ref="myEchart"></div></el-col>
<el-col :span="6"><div id = "echartss1" class="echarts-div" ref="myEchart1"></div></el-col>
<el-col :span="6"><div id = "echartss2" class="echarts-div" ref="myEchart2"></div></el-col>
<el-col :span="6"><div id = "echartss3" class="echarts-div" ref="myEchart3"></div></el-col>
</el-row>
<el-row :gutter="20" class="echarts-row">
<el-col :span="6"><div id = "echartss4" class="echarts-div" ref="myEchart4"></div></el-col>
<el-col :span="6"><div id = "echartss5" class="echarts-div" ref="myEchart5"></div></el-col>
<el-col :span="6"><div id = "echartss6" class="echarts-div" ref="myEchart6"></div></el-col>
<el-col :span="6"><div id = "echartss7" class="echarts-div" ref="myEchart7"></div></el-col>
</el-row>
<!-- <el-row :gutter="20" class="echarts-row">
<el-col :span="6"><div id = "echartss8" class="echarts-div" ref="myEchart8"></div></el-col>
<el-col :span="6"><div id = "echartss9" class="echarts-div" ref="myEchart9"></div></el-col>
<el-col :span="6"><div id = "echartss10" class="echarts-div" ref="myEchart10"></div></el-col>
<el-col :span="6"><div id = "echartss11" class="echarts-div" ref="myEchart11"></div></el-col>
</el-row>
<el-row :gutter="20" class="echarts-row">
<el-col :span="6"><div id = "echartss12" class="echarts-div" ref="myEchart12"></div></el-col>
<el-col :span="6"><div id = "echartss13" class="echarts-div" ref="myEchart13"></div></el-col>
<el-col :span="6"><div id = "echartss14" class="echarts-div" ref="myEchart14"></div></el-col>
<el-col :span="6"><div id = "echartss15" class="echarts-div" ref="myEchart15"></div></el-col>
</el-row> -->
</div>
</template>
<script>
import echarts from 'echarts'
let data = []
for (var i = 0; i <= 360; i++) {
var t = i / 180 * Math.PI
var r = Math.sin(2 * t) * Math.cos(2 * t)
data.push([r, i])
}
export default {
// 挂载前初始化echarts实例
mounted: function () {
// 基于准备好的dom,初始化echarts实例
this.myChart = echarts.init(this.$refs.myEchart)
// 绘制图表,this.echarts1_option是数据
this.myChart.setOption(this.echarts_option)
this.myChart1 = echarts.init(this.$refs.myEchart1)
this.myChart1.setOption(this.echarts1_option)
this.myChart2 = echarts.init(this.$refs.myEchart2)
this.myChart2.setOption(this.echarts2_option)
this.myChart3 = echarts.init(this.$refs.myEchart3)
this.myChart3.setOption(this.echarts3_option)
this.myChart4 = echarts.init(this.$refs.myEchart4)
this.myChart4.setOption(this.echarts4_option)
},
data () {
return {
echarts4_option: {
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b}: {c} ({d}%)'
},
legend: {
orient: 'vertical',
x: 'left',
data: ['直接访问', '邮件营销', '联盟广告', '视频广告', '搜索引擎']
},
series: [
{
name: '访问来源',
type: 'pie',
radius: ['50%', '70%'],
avoidLabelOverlap: false,
label: {
normal: {
show: false,
position: 'center'
},
emphasis: {
show: true,
textStyle: {
fontSize: '30',
fontWeight: 'bold'
}
}
},
labelLine: {
normal: {
show: false
}
},
data: [
{ value: 335, name: '直接访问' },
{ value: 310, name: '邮件营销' },
{ value: 234, name: '联盟广告' },
{ value: 135, name: '视频广告' },
{ value: 1548, name: '搜索引擎' }
]
}
]
},
echarts3_option: {
title: {
text: '简单柱状图'
},
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [{
data: [120, 200, 150, 80, 70, 110, 130],
type: 'bar'
}]
},
echarts2_option: {
title: {
text: '极坐标双数值轴'
},
legend: {
data: ['line']
},
polar: {
center: ['50%', '54%']
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
}
},
angleAxis: {
type: 'value',
startAngle: 0
},
radiusAxis: {
min: 0
},
series: [{
coordinateSystem: 'polar',
name: 'line',
type: 'line',
showSymbol: false,
data: data
}],
animationDuration: 2000
},
echarts_option: {
title: {
text: '折线图'
},
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [{
data: [820, 932, 901, 934, 1290, 1330, 1320],
type: 'line'
}]
},
echarts1_option: {
title: {
text: '折线图堆叠'
},
tooltip: {
trigger: 'axis'
},
// legend: {
// data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎']
// },
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
},
yAxis: {
type: 'value'
},
series: [
{
name: '邮件营销',
type: 'line',
stack: '总量',
data: [120, 132, 101, 134, 90, 230, 210]
},
{
name: '联盟广告',
type: 'line',
stack: '总量',
data: [220, 182, 191, 234, 290, 330, 310]
},
{
name: '视频广告',
type: 'line',
stack: '总量',
data: [150, 232, 201, 154, 190, 330, 410]
},
{
name: '直接访问',
type: 'line',
stack: '总量',
data: [320, 332, 301, 334, 390, 330, 320]
},
{
name: '搜索引擎',
type: 'line',
stack: '总量',
data: [820, 932, 901, 934, 1290, 1330, 1320]
}
]
}
}
}
}
</script>
<style scoped>
.echarts-row {
height: 300px;
}
.echarts-div {
width: 100%;
height: 300px;
}
</style>
- Export.vue
这里有一个导出,和模拟修改用户信息的按钮
<template>
<div>
<el-button type='success' plain size='small' @click='export2Excel'>导出excel</el-button>
<el-button type='success' plain size='small' @click='updateUser'>修改登录用户</el-button>
</div>
</template>
<script>
// import Blob from '@/assets/excel/Blob'
// import Export2Excel from '@/assets/excel/Export2Excel.js'
export default {
data () {
return {
tableData: [
{ 'index': '0', 'nickName': '沙滩搁浅我们的旧时光', 'name': '小明' },
{ 'index': '1', 'nickName': '女人天生高贵', 'name': '小红' },
{ 'index': '2', 'nickName': '海是彩色的灰尘', 'name': '小兰' }
]
}
},
methods: {
export2Excel: function () {
require.ensure([], () => {
const { exportJsonToExcel } = require('@/assets/excel/Export2Excel')
const tHeader = ['序号', '昵称', '姓名']
// 上面设置Excel的表格第一行的标题
const filterVal = ['index', 'nickName', 'name']
// 上面的index、nickName、name是tableData里对象的属性
let list = []
// const list = this.tableData
let d = { 'index': '0', 'nickName': '沙滩搁浅我们的旧时光', 'name': '小明' }
for (let a = 0; a < 100000; a++) {
list.push(d)
}
// 把data里的tableData存到list
const data = this.formatJson(filterVal, list)
// console.log(data)
exportJsonToExcel(tHeader, data, '列表excel')
})
},
formatJson (filterVal, jsonData) {
return jsonData.map(v => filterVal.map(j => v[j]))
},
updateUser () {
let userInfo = {
name: 'UpdateUser',
img: 'https://raw.githubusercontent.com/taylorchen709/markdown-images/master/vueadmin/user.png'
}
this.$store.commit('login', userInfo)
}
}
}
</script>
- Home.vue(demo中的首页)
<template>
<el-row >
<el-col :span="24" class="disc">
<h3>关于本DEMO</h3>
<div>后端工程师写vue之路。</div>
<div>使用vue、element ui作为基础的脚手架。在这个基础上进一步的做了优化,使得在以后得开发过程中只关注业务,不需要考虑整体的结构。</div>
</el-col>
<el-col :span="24" class="disc">
<h3>启动</h3>
<div>
npm run serve 默认启动<br>
npm run serve-dev 启动dev环境<br>
npm run serve-local 启动local环境
</div>
</el-col>
<el-col :span="24" class="disc">
<h3>打包</h3>
<div>
npm run build 全部工程打包<br>
npm run build-test demo 指定环境和项目打包<br>
npm run build-prod demo 指定环境和项目打包
</div>
</el-col>
</el-row>
</template>
<script>
export default {
}
</script>
<style>
.disc {
padding-left: 10px
}
</style>
- Login.vue
<template>
<div class="login-main">
<el-row class="login">
<el-col :span="4" :offset="6">
<div class="login-info">
<div>VUE</div>
<div>VUEX</div>
<div>router</div>
<div>element UI</div>
<div>echarts</div>
<div>......</div>
</div>
</el-col>
<el-col :span="6" :offset="3">
<div class="login-div">
<h3>登录</h3>
<el-form :model="login" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
<el-form-item label="用户名称" prop="name">
<el-input v-model="login.name" ></el-input>
</el-form-item>
<el-form-item label="登录密码" prop="pwd">
<el-input v-model="login.pwd"></el-input>
</el-form-item>
<el-form-item>
<el-button type="success" @click="updateUser('ruleForm')">模拟登录</el-button>
<el-button @click="resetForm('ruleForm')">重置</el-button>
</el-form-item>
</el-form>
</div>
</el-col>
</el-row>
</div>
</template>
<script>
export default {
data () {
return {
'login': {
'name': '',
'pwd': ''
},
rules: {
name: [
{ required: true, message: '请输入用户名称', trigger: 'blur' },
{ min: 5, max: 20, message: '长度在 5 到 20 个字符', trigger: 'blur' }
],
pwd: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, max: 20, message: '长度在 6 到 20 个字符', trigger: 'blur' }
]
}
}
},
methods: {
updateUser (formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
let userInfo = {
name: this.login.name,
img: 'https://raw.githubusercontent.com/taylorchen709/markdown-images/master/vueadmin/user.png'
}
this.$store.commit('login', userInfo)
// 如果存在参数
if (this.$route.query.redirect) {
let redirect = this.$route.query.redirect
// 则跳转至进入登录页前的路由
this.$router.push(redirect)
} else {
// 否则跳转至首页
this.$router.push('/main/home')
}
} else {
console.log('error submit!!')
return false
}
})
},
resetForm (formName) {
this.$refs[formName].resetFields()
}
}
}
</script>
<style>
.login-main{
width: 100%;
height: 100%;
}
.login{
margin-top: 15%;
background-color: #67C23A
}
.login-info{
height: 100%;
padding: 20px 0 0 0;
}
.login-info>div{
margin-bottom: 20px;
font-size: 20px;
}
.login-div{
padding: 20px 60px 40px 40px;
background-color: #eef1f6
}
body{
margin: 0px;
}
</style>
- MyMain.vue
<template>
<div id="app">
<Home :sysName='sysName' :userInfo='userInfo' :menuJson='menuJson' @logoutHandle='logoutHandle'/>
<!-- <router-view/> -->
</div>
</template>
<script>
import Home from '@/components/Home.vue'
import axios from '../utils/http'
// 用户
// let userInfo = {
// name: '苏三杰',
// img: 'https://raw.githubusercontent.com/taylorchen709/markdown-images/master/vueadmin/user.png'
// }
// 系统名称
let sysName = 'WXD-DEMO'
// 菜单
let menuJson = [
{
id: '1',
name: '首页',
type: 'menu-item',
url: '/main/home',
icon: 'el-icon-star-off',
submenus: []
},
{
id: '2',
name: 'TableS',
type: 'subMenu',
url: '',
icon: 'el-icon-s-grid',
submenus: [
{
id: '3',
name: '动态table',
type: 'subMenu',
url: '/main/about',
icon: ''
},
{
id: '4',
name: '拖拽table',
type: 'subMenu',
url: '/main/about1',
icon: ''
},
{
id: '5',
name: '综合table',
type: 'subMenu',
url: '/main/about2',
icon: ''
}
]
},
{
id: '6',
name: '列表demo',
type: 'subMenu',
url: '',
icon: 'el-icon-user',
submenus: [
{
id: '7',
name: '用户列表',
type: 'subMenu',
url: '/main/user',
icon: ''
},
{
id: '8',
name: '订单列表',
type: 'subMenu',
url: '/main/order',
icon: ''
}
]
},
{
id: '9',
name: '工具demo',
type: 'subMenu',
url: '',
icon: 'el-icon-setting',
submenus: [
{
id: '10',
name: '常用报表',
type: 'subMenu',
url: '/main/echarts',
icon: ''
},
{
id: '11',
name: '常用图标',
type: 'subMenu',
url: '/main/ioc',
icon: ''
},
{
id: '12',
name: '导出demo',
type: 'subMenu',
url: '/main/export',
icon: ''
}
]
}
]
export default {
components: {
Home
},
data () {
return {
// 'userInfo': this.$store.state.userInfo,
'sysName': sysName,
'menuJson': menuJson
}
},
computed: {
'userInfo': function () {
return this.$store.state.userInfo
}
},
methods: {
logoutHandle: function () {
// TODO
console.log('退出')
this.$store.commit('login', {})
this.$router.push({ 'path': '/login' })
},
testApi: function () {
// http://10.98.3.27:8080/app/mock/data/139
axios
.get('http://10.98.3.27:8080/app/mock/data/139')
.then(response => {
console.info(response)
console.info(response.data)
})
.catch(error => {
console.log(error)
})
.finally(() => console.log('finally'))
}
},
created: function () {
// this.testApi()
// this.$router.push({ 'path': '/login' })
console.log(this.$store.state)
}
}
</script>
<style>
</style>
- Order.vue
<template>
<CommonPage :formEntity="formEntity" :queryFunction="queryF" :tableEntity="tableEntity" :buttons="buttons"></CommonPage>
</template>
<script>
import CommonPage from '@/components/CommonPage.vue'
// 查询表单数组
let formEntityDemo = [
{
template: 'input',
type: 'string',
name: 'name',
label: '用户名',
placeholder: '用户名'
},
{
template: 'input',
type: 'number',
name: 'age',
label: '年龄',
placeholder: '年龄'
},
{
template: 'date',
type: 'date',
name: 'birthday',
label: '生日',
placeholder: '生日'
},
{
template: 'date',
type: 'month',
name: 'month',
label: '月份',
placeholder: '月份'
},
{
template: 'date',
type: 'monthrange',
name: 'monthrange',
label: '月份区间',
'range-separator': '至',
'start-placeholder': '开始月份',
'end-placeholder': '结束月份',
placeholder: '月份区间'
},
{
template: 'date',
type: 'daterange',
name: 'qutime',
label: '日期区间',
'start-placeholder': '开始日期',
'end-placeholder': '结束日期',
'default-time': ['00:00:00', '23:59:59'],
placeholder: '日期区间'
},
{
template: 'select',
type: 'select',
name: 'region',
label: '活动区域',
placeholder: '活动区域',
options: [
{
label: '区域一',
value: 'shanghai'
},
{
label: '区域二',
value: 'beijing'
},
{
label: '区域三',
value: 'shanxi'
}
]
}
]
// 数据列表
let users = [
{
'id': 1,
'name': '刘娟',
'sex': 1,
'age': 23,
'addr': '香港特别行政区 新界 西贡区',
'orderNo': '001',
'amount': 200
},
{
'id': 1,
'name': '刘娟',
'sex': 0,
'age': 23,
'addr': '香港特别行政区 新界 西贡区',
'orderNo': '002',
'amount': 200
},
{
'id': 1,
'name': '刘娟',
'sex': 1,
'age': 23,
'addr': '香港特别行政区 新界 西贡区',
'orderNo': '003',
'amount': 200
},
{
'id': 1,
'name': '刘娟',
'sex': 0,
'age': 23,
'addr': '香港特别行政区 新界 西贡区',
'orderNo': '004',
'amount': 200
},
{
'id': 1,
'name': '刘娟',
'sex': 1,
'age': 23,
'addr': '香港特别行政区 新界 西贡区',
'orderNo': '005',
'amount': 200
},
{
'id': 1,
'name': '刘娟',
'sex': 1,
'age': 23,
'addr': '香港特别行政区 新界 西贡区',
'orderNo': '006',
'amount': 200
},
{
'id': 1,
'name': '刘娟',
'sex': 0,
'age': 23,
'addr': '香港特别行政区 新界 西贡区',
'orderNo': '007',
'amount': 200
},
{
'id': 1,
'name': '刘娟',
'sex': 1,
'age': 23,
'addr': '香港特别行政区 新界 西贡区',
'orderNo': '008',
'amount': 200
},
{
'id': 1,
'name': '刘娟',
'sex': 0,
'age': 23,
'addr': '香港特别行政区 新界 西贡区',
'orderNo': '009',
'amount': 200
},
{
'id': 1,
'name': '刘娟',
'sex': 1,
'age': 23,
'addr': '香港特别行政区 新界 西贡区',
'orderNo': '010',
'amount': 200
},
{
'id': 1,
'name': '刘娟',
'sex': 1,
'age': 23,
'addr': '香港特别行政区 新界 西贡区',
'orderNo': '011',
'amount': 200
},
{
'id': 1,
'name': '刘娟',
'sex': 0,
'age': 23,
'addr': '香港特别行政区 新界 西贡区',
'orderNo': '012',
'amount': 200
},
{
'id': 1,
'name': '刘娟',
'sex': 1,
'age': 23,
'addr': '香港特别行政区 新界 西贡区',
'orderNo': '012',
'amount': 200
},
{
'id': 1,
'name': '刘娟',
'sex': 0,
'age': 23,
'addr': '香港特别行政区 新界 西贡区',
'orderNo': '012',
'amount': 200
},
{
'id': 1,
'name': '刘娟',
'sex': 1,
'age': 23,
'addr': '香港特别行政区 新界 西贡区',
'orderNo': '012',
'amount': 200
},
{
'id': 1,
'name': '刘娟',
'sex': 1,
'age': 23,
'addr': '香港特别行政区 新界 西贡区',
'orderNo': '012',
'amount': 200
},
{
'id': 1,
'name': '刘娟',
'sex': 1,
'age': 23,
'addr': '香港特别行政区 新界 西贡区',
'orderNo': '012',
'amount': 200
},
{
'id': 1,
'name': '刘娟',
'sex': 1,
'age': 23,
'addr': '香港特别行政区 新界 西贡区',
'orderNo': '012',
'amount': 200
},
{
'id': 1,
'name': '刘娟',
'sex': 1,
'age': 23,
'addr': '香港特别行政区 新界 西贡区',
'orderNo': '012',
'amount': 200
},
{
'id': 1,
'name': '刘娟',
'sex': 1,
'age': 23,
'addr': '香港特别行政区 新界 西贡区',
'orderNo': '012',
'amount': 200
}
]
// 列表属性
let tableDemo = {
page: {
currentPage: 1,
total: 1400,
// 改变每页记录数
handleSizeChange: (size) => {
console.log('order页面' + size)
},
// 点击其他页面
handleCurrentChange: (currentPage) => {
console.log('order页面' + currentPage)
}
},
options: {
// 数据
'datas': users,
// 表格属性
tableAttrs: {
'size': 'small',
'border': true
},
// 表格事件
tableEvents: {
'select': function (selection, row) {
console.log(selection)
console.log('order页面' + selection)
}
},
// 列 不包括操作列
columns: [
{
'type': 'selection',
'width': '55'
},
{
'type': 'index',
'label': '序号',
'width': '60'
},
{
'prop': 'orderNo',
'label': '订单号',
'width': '120'
},
{
'prop': 'amount',
'label': '金额',
'width': '120'
},
{
'prop': 'name',
'label': '姓名',
'width': '120'
},
{
'prop': 'sex',
'label': '性别',
'width': '120',
'formatter': function (row, column) {
return row.sex === 1 ? '男' : row.sex === 0 ? '女' : '未知'
}
},
{
'prop': 'age',
'label': '年龄',
'width': '120'
},
{
'prop': 'addr',
'label': '收货地址',
'width': '250'
}
],
// 操作列
operationColumn: [
{
'label': '编辑',
'type': 'primary',
'callback': (index, row) => {
console.log(row)
}
},
{
'label': '查看',
'type': 'danger',
'callback': (index, row) => {
console.log(row)
}
}
]
}
}
// 按钮
let buttons = [
{
'label': '添加订单',
'type': 'primary',
'callback': () => {
console.log('添加订单')
}
},
{
'label': '修改订单',
'type': 'warning',
'callback': () => {
console.log('修改订单')
}
},
{
'label': '删除订单',
'type': 'danger',
'callback': () => {
console.log('删除订单')
}
},
{
'label': '订单详情',
'type': 'info',
'callback': () => {
console.log('订单详情')
}
}
]
export default {
components: {
CommonPage
},
data () {
return {
formEntity: formEntityDemo,
tableEntity: tableDemo,
buttons: buttons
}
},
methods: {
// 查询方法
queryF: function (a) {
// 查询的实体
console.log(a)
}
}
}
</script>
- User.vue
<template>
<div>
<el-row :gutter="10">
<el-col :span="24">
<div class="bg-purple-dark">
<el-form :inline="true" :model="formInline">
<el-form-item label="用户名">
<el-input v-model="formInline.user" size="small" placeholder="用户名"></el-input>
</el-form-item>
<el-form-item label="用户名">
<el-input v-model="formInline.user" size="small" placeholder="用户名"></el-input>
</el-form-item>
<el-form-item label="用户名">
<el-input v-model="formInline.user" size="small" placeholder="用户名"></el-input>
</el-form-item>
<el-form-item label="用户名">
<el-input v-model="formInline.user" size="small" placeholder="用户名"></el-input>
</el-form-item>
<el-form-item label="用户名">
<el-input v-model="formInline.user" size="small" placeholder="用户名"></el-input>
</el-form-item>
<el-form-item label="活动区域">
<el-select v-model="formInline.region" size="small" placeholder="活动区域">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" size="small">查询</el-button>
</el-form-item>
</el-form>
</div>
</el-col>
</el-row>
<el-row>
<el-button plain size="small">朴素按钮</el-button>
<el-button type="primary" plain size="small" @click="userAdd">添加用户</el-button>
<el-button type="success" plain size="small">成功按钮</el-button>
<el-button type="info" plain size="small">信息按钮</el-button>
<el-button type="warning" plain size="small">警告按钮</el-button>
<el-button type="danger" plain size="small" @click="userDel">删除用户</el-button>
</el-row>
<el-row>
<Table v-bind="options">
<el-table-column label="操作" width="150">
<template scope="scope">
<el-button size="mini" @click="handleEdit(scope.$index, scope.row)">编辑</el-button>
<el-button plain type="danger" size="mini" @click="handleDel(scope.$index, scope.row)">删除</el-button>
</template>
</el-table-column>
</Table>
</el-row>
<el-row style="background: #f2f2f2;">
<div class="bg-purple-dark">
<Page
:currentPage="currentPage"
:total="total"
@handleSizeChange="handleSizeChange"
@handleCurrentChange="handleCurrentChange"
/>
</div>
</el-row>
<UserAdd ref="userAddView" :pdialogFormVisible="pdialogFormVisible"/>
</div>
</template>
<script>
import Table from '@/components/Table.vue'
import Page from '@/components/Page.vue'
import UserAdd from './UserAdd.vue'
let users = [
{
'id': 1,
'name': '刘娟',
'sex': 1,
'age': 23,
'addr': '香港特别行政区 新界 西贡区'
},
{
'id': 1,
'name': '刘娟',
'sex': 0,
'age': 23,
'addr': '香港特别行政区 新界 西贡区'
},
{
'id': 1,
'name': '刘娟',
'sex': 1,
'age': 23,
'addr': '香港特别行政区 新界 西贡区'
},
{
'id': 1,
'name': '刘娟',
'sex': 0,
'age': 23,
'addr': '香港特别行政区 新界 西贡区'
},
{
'id': 1,
'name': '刘娟',
'sex': 1,
'age': 23,
'addr': '香港特别行政区 新界 西贡区'
},
{
'id': 1,
'name': '刘娟',
'sex': 1,
'age': 23,
'addr': '香港特别行政区 新界 西贡区'
},
{
'id': 1,
'name': '刘娟',
'sex': 0,
'age': 23,
'addr': '香港特别行政区 新界 西贡区'
},
{
'id': 1,
'name': '刘娟',
'sex': 1,
'age': 23,
'addr': '香港特别行政区 新界 西贡区'
},
{
'id': 1,
'name': '刘娟',
'sex': 0,
'age': 23,
'addr': '香港特别行政区 新界 西贡区'
},
{
'id': 1,
'name': '刘娟',
'sex': 1,
'age': 23,
'addr': '香港特别行政区 新界 西贡区'
},
{
'id': 1,
'name': '刘娟',
'sex': 1,
'age': 23,
'addr': '香港特别行政区 新界 西贡区'
},
{
'id': 1,
'name': '刘娟',
'sex': 0,
'age': 23,
'addr': '香港特别行政区 新界 西贡区'
},
{
'id': 1,
'name': '刘娟',
'sex': 1,
'age': 23,
'addr': '香港特别行政区 新界 西贡区'
},
{
'id': 1,
'name': '刘娟',
'sex': 0,
'age': 23,
'addr': '香港特别行政区 新界 西贡区'
},
{
'id': 1,
'name': '刘娟',
'sex': 1,
'age': 23,
'addr': '香港特别行政区 新界 西贡区'
}
]
// let selectedIds = []
export default {
components: {
Table,
Page,
UserAdd
},
data () {
var _this = this
return {
pdialogFormVisible: false,
currentPage: 4,
total: 1400,
selectedIds: [],
formInline: {
user: '',
region: ''
},
options: {
'datas': users,
tableAttrs: {
'size': 'small',
'border': true
},
tableEvents: {
'select': function (selection, row) {
_this.selectedIds = selection.map(u => {
return u.id
})
}
},
columns: [
{
'type': 'selection',
'width': '55'
},
{
'type': 'index',
'label': '序号',
'width': '60'
},
{
'prop': 'name',
'label': '姓名',
'width': '120'
},
{
'prop': 'sex',
'label': '性别',
'width': '120',
'formatter': function (row, column) {
return row.sex === 1 ? '男' : row.sex === 0 ? '女' : '未知'
}
},
{
'prop': 'age',
'label': '年龄',
'width': '120'
},
{
'prop': 'addr',
'label': '地址',
'width': '250'
}
]
}
}
},
methods: {
userDel () {
// 获取选中的用户id
if (this.selectedIds.length === 0) {
this.$alert('请选择要删除的用户', '提示', {
confirmButtonText: '确定',
callback: function () {
// do something
}
})
return
}
this.$confirm('此操作将永久删除该用户, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
// 正真的删除
this.$message({
type: 'success',
message: '删除成功!'
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
})
})
},
userAdd () {
this.$refs.userAddView.opendialog()
// this.pdialogFormVisible = true
// console.log(this.pdialogFormVisible)
},
handleEdit: function (index, row) {
console.log(index)
console.log(row)
},
handleSizeChange (val) {
console.log('每页 条' + val)
},
handleCurrentChange (val) {
console.log('当前页: ' + val)
},
setSelectedIds (ids) {
this.selectedIds = ids
}
}
}
</script>
<style scoped>
.bg-purple-dark {
border-radius: 4px;
background: #EEF1F6;
padding: 10px;
}
.el-form-item {
margin: 5px;
}
.el-row {
margin-bottom: 5px;
}
</style>
- UserAdd.vue
<template>
<el-dialog title="收货地址" :visible.sync="dialogFormVisible">
<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
<el-form-item label="活动名称" prop="name">
<el-input v-model="ruleForm.name"></el-input>
</el-form-item>
<el-form-item label="活动区域" prop="region">
<el-select v-model="ruleForm.region" placeholder="请选择活动区域">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
<el-form-item label="活动时间" required>
<el-col :span="11">
<el-form-item prop="date1">
<el-date-picker type="date" placeholder="选择日期" v-model="ruleForm.date1" style="width: 100%;"></el-date-picker>
</el-form-item>
</el-col>
<el-col class="line" :span="2">-</el-col>
<el-col :span="11">
<el-form-item prop="date2">
<el-time-picker placeholder="选择时间" v-model="ruleForm.date2" style="width: 100%;"></el-time-picker>
</el-form-item>
</el-col>
</el-form-item>
<el-form-item label="即时配送" prop="delivery">
<el-switch v-model="ruleForm.delivery"></el-switch>
</el-form-item>
<el-form-item label="活动性质" prop="type">
<el-checkbox-group v-model="ruleForm.type">
<el-checkbox label="美食/餐厅线上活动" name="type"></el-checkbox>
<el-checkbox label="地推活动" name="type"></el-checkbox>
<el-checkbox label="线下主题活动" name="type"></el-checkbox>
<el-checkbox label="单纯品牌曝光" name="type"></el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="特殊资源" prop="resource">
<el-radio-group v-model="ruleForm.resource">
<el-radio label="线上品牌商赞助"></el-radio>
<el-radio label="线下场地免费"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="活动形式" prop="desc">
<el-input type="textarea" v-model="ruleForm.desc"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button @click="resetForm('ruleForm')">重置</el-button>
<el-button type="primary" @click="submitForm('ruleForm')">确 定</el-button>
</div>
</el-dialog>
</template>
<script>
export default {
props: ['pdialogFormVisible'],
data () {
return {
'dialogFormVisible': this.pdialogFormVisible,
ruleForm: {
name: '',
region: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: ''
},
rules: {
name: [
{ required: true, message: '请输入活动名称', trigger: 'blur' },
{ min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'blur' }
],
region: [
{ required: true, message: '请选择活动区域', trigger: 'change' }
],
date1: [
{ type: 'date', required: true, message: '请选择日期', trigger: 'change' }
],
date2: [
{ type: 'date', required: true, message: '请选择时间', trigger: 'change' }
],
type: [
{ type: 'array', required: true, message: '请至少选择一个活动性质', trigger: 'change' }
],
resource: [
{ required: true, message: '请选择活动资源', trigger: 'change' }
],
desc: [
{ required: true, message: '请填写活动形式', trigger: 'blur' }
]
}
}
},
methods: {
submitForm (formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
alert('submit!')
this.dialogFormVisible = false
} else {
console.log('error submit!!')
return false
}
})
},
resetForm (formName) {
this.$refs[formName].resetFields()
},
opendialog () {
if (this.dialogFormVisible) {
return
}
this.dialogFormVisible = true
}
},
created () {
}
}
</script>
OK、主要的代码就完成了。
启动后的效果图:
以上就完成了一个简单的demo。
源码地址:https://github.com/1065744299/vue-elment-ui
如果对你有帮助,可以请作者喝杯咖啡: