vue2+element ui

本文档展示了后端人员如何使用vue2、vueRouter、vueX和element UI构建一个包含登录、路由、状态管理、报表和导出功能的后台管理框架。提供了项目结构、关键组件介绍及代码修改说明,包括Home、Head、Main、Menu、Table等组件的使用。源码可在GitHub和优快云下载。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

后端人员开发前端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。

主要有几个基础的组件。
先了解下项目结构:
在这里插入图片描述
了解vue的应该知道初始化以后就会有这些目录
这里主要说组件的内容。

  • 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

如果对你有帮助,可以请作者喝杯咖啡:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值