3. Yunshang Office - role management front end

Yunshang Office System: role management front-end

Direct access to station B [like Silicon Valley]:
https://www.bilibili.com/video/BV1Ya411S7aT

This blog post is mainly published related to the course, and incorporates some of my own opinions and gives relevant solutions to the problems encountered in the learning process. Learn together and progress together! ! !

problem solved

Everyone who integrates needs to be careful to avoid mistakes caused by carelessness, and then here is the solution to using the 18 version of Node in the previous blog post: find the
package.json file
and add:

"dev_t": "set NODE_OPTIONS=\"--openssl-legacy-provider\" & npm run dev\n"

Then after the front-end dependency download is complete, enter in the terminal

npm run dev_t

insert image description here

1. Front-end framework

1、vue-element-admin

Vue-element-admin is a background management system integration solution based on element-ui.

**Function:**https://panjiachen.github.io/vue-element-admin-site/zh/guide/#function

**GitHub address:**https://github.com/PanJiaChen/vue-element-admin

Project online preview: https://panjiachen.gitee.io/vue-element-admin

2、vue-admin-template

2.1. Introduction

vue-admin-template is a set of background management system basic templates (minimum simplified version) based on vue-element-admin, which can be used as templates for secondary development.

**GitHub address:**https://github.com/PanJiaChen/vue-admin-template

**Suggestion:** You can vue-admin-templatecarry out secondary development on the basis of , use vue-element-adminit as a toolbox, and copy any functions or components you want from vue-element-adminthere.

2.2. Installation

#修改项目名称 vue-admin-template 改为 guigu-auth-ui
# 解压压缩包
# 进入目录
cd guigu-auth-ui
# 安装依赖
npm install
# 启动。执行后,浏览器自动弹出并访问http://localhost:9528/
npm run dev
// 如果是高版本就用npm run dev_t(已经改过文件的)

2.3. Source code directory structure

|-dist 生产环境打包生成的打包项目
|-mock 使用mockjs来mock接口
|-public 包含会被自动打包到项目根路径的文件夹
	|-index.html 唯一的页面
|-src
	|-api 包含接口请求函数模块
		|-table.js  表格列表mock数据接口的请求函数
		|-user.js  用户登陆相关mock数据接口的请求函数
	|-assets 组件中需要使用的公用资源
		|-404_images 404页面的图片
	|-components 非路由组件
		|-SvgIcon svg图标组件
		|-Breadcrumb 面包屑组件(头部水平方向的层级组件)
		|-Hamburger 用来点击切换左侧菜单导航的图标组件
	|-icons
		|-svg 包含一些svg图片文件
		|-index.js 全局注册SvgIcon组件,加载所有svg图片并暴露所有svg文件名的数组
	|-layout
		|-components 组成整体布局的一些子组件
		|-mixin 组件中可复用的代码
		|-index.vue 后台管理的整体界面布局组件
	|-router
		|-index.js 路由器
	|-store
		|-modules
			|-app.js 管理应用相关数据
			|-settings.js 管理设置相关数据
			|-user.js 管理后台登陆用户相关数据
		|-getters.js 提供子模块相关数据的getters计算属性
		|-index.js vuex的store
	|-styles
		|-xxx.scss 项目组件需要使用的一些样式(使用scss)
	|-utils 一些工具函数
		|-auth.js 操作登陆用户的token cookie
		|-get-page-title.js 得到要显示的网页title
		|-request.js axios二次封装的模块
		|-validate.js 检验相关工具函数
		|-index.js 日期和请求参数处理相关工具函数
	|-views 路由组件文件夹
		|-dashboard 首页
		|-login 登陆
	|-App.vue 应用根组件
	|-main.js 入口js
	|-permission.js 使用全局守卫实现路由权限控制的模块
	|-settings.js 包含应用设置信息的模块
|-.env.development 指定了开发环境的代理服务器前缀路径
|-.env.production 指定了生产环境的代理服务器前缀路径
|-.eslintignore eslint的忽略配置
|-.eslintrc.js eslint的检查配置
|-.gitignore git的忽略配置
|-.npmrc 指定npm的淘宝镜像和sass的下载地址
|-babel.config.js babel的配置
|-jsconfig.json 用于vscode引入路径提示的配置
|-package.json 当前项目包信息
|-package-lock.json 当前项目依赖的第三方包的精确信息
|-vue.config.js webpack相关配置(如: 代理服务器)

2.4. Realize login & logout

2.4.1、vue.config.js
  • Comment out the mock interface configuration
  • Configure the proxy to forward requests to the target interface
// before: require('./mock/mock-server.js')
proxy: {
    
    
  '/dev-api': {
    
     // 匹配所有以 '/dev-api'开头的请求路径
    target: 'http://localhost:8800',
    changeOrigin: true, // 支持跨域
    pathRewrite: {
    
     // 重写路径: 去掉路径中开头的'/dev-api'
      '^/dev-api': ''
    }
  }
}
2.4.2、utils/request.js

The request automatically carries the token, and the request header name is token

const token = store.getters.token
if (token) {
    
    
  // let each request carry token
  // ['X-Token'] is a custom headers key
  // please modify it according to the actual situation
  // config.headers['X-Token'] = getToken()
  config.headers['token'] = token
}
if (res.code !== 200) {
    
    
  Message({
    
    
    message: res.message || 'Error',
    type: 'error',
    duration: 5 * 1000
  })
  return Promise.reject(new Error(res.message || 'Error'))
} else {
    
    
  return res
}
2.4.3、api/user.js
import request from '@/utils/request'

export function login(data) {
    
    
  return request({
    
    
    url: '/admin/system/index/login',
    method: 'post',
    data
  })
}

export function getInfo(token) {
    
    
  return request({
    
    
    url: '/admin/system/index/info',
    method: 'get',
    params: {
    
     token }
  })
}

export function logout() {
    
    
  return request({
    
    
    url: '/admin/system/index/logout',
    method: 'post'
  })
}
2.4.5. Add interface on the server side
package com.atguigu.system.controller;

import com.atguigu.common.result.Result;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * 后台登录登出
 * </p>
 */
@Api(tags = "后台登录管理")
@RestController
@RequestMapping("/admin/system/index")
public class IndexController {
    
    


    /**
     * 登录
     * @return
     */
    @PostMapping("login")
    public Result login() {
    
    
        Map<String, Object> map = new HashMap<>();
        map.put("token","admin");
        return Result.ok(map);
    }
    /**
     * 获取用户信息
     * @return
     */
    @GetMapping("info")
    public Result info() {
    
    
        Map<String, Object> map = new HashMap<>();
        map.put("roles","[admin]");
        map.put("name","admin");
        map.put("avatar","https://oss.aliyuncs.com/aliyun_id_photo_bucket/default_handsome.jpg");
        return Result.ok(map);
    }
    /**
     * 退出
     * @return
     */
    @PostMapping("logout")
    public Result logout(){
    
    
        return Result.ok();
    }

}
2.4.5、store/modules/user.js

No need to specify the token parameter

getInfo({
     
      commit, state }) {
    
    
  return new Promise((resolve, reject) => {
    
    
    getInfo().then(response => {
    
    
      const {
    
     data } = response

      if (!data) {
    
    
        return reject('Verification failed, please Login again.')
      }

      const {
    
     name, avatar } = data

      commit('SET_NAME', name)
      commit('SET_AVATAR', avatar)
      resolve(data)
    }).catch(error => {
    
    
      reject(error)
    })
  })
},
2.4.6、views/login/index.vue

change page title

<div class="title-container">
  <h3 class="title">硅谷通用权限系统</h3>
</div>

Username check only checks length

const validateUsername = (rule, value, callback) => {
    
    
  if (value.length<5) {
    
    
    callback(new Error('Please enter the correct user name'))
  } else {
    
    
    callback()
  }
}
const validatePassword = (rule, value, callback) => {
    
    
  if (value.length < 6) {
    
    
    callback(new Error('The password can not be less than 6 digits'))
  } else {
    
    
    callback()
  }
}
2.4.7、src/router/index.js

delete redundant routes

export const constantRoutes = [
  {
    
    
    path: '/login',
    component: () => import('@/views/login/index'),
    hidden: true
  },

  {
    
    
    path: '/404',
    component: () => import('@/views/404'),
    hidden: true
  },

  {
    
    
    path: '/',
    component: Layout,
    redirect: '/dashboard',
    children: [{
    
    
      path: 'dashboard',
      name: 'Dashboard',
      component: () => import('@/views/dashboard/index'),
      meta: {
    
     title: 'Dashboard', icon: 'dashboard' }
    }]
  },

  // 404 page must be placed at the end !!!
  {
    
     path: '*', redirect: '/404', hidden: true }
]
2.4.8. Test login

2. List of roles

1. Modify the route

Modify the src/router/index.js file and redefine constantRoutes

 export const constantRoutes = [
  {
    
    
    path: '/login',
    component: () => import('@/views/login/index'),
    hidden: true
  },

  {
    
    
    path: '/404',
    component: () => import('@/views/404'),
    hidden: true
  },

  {
    
    
    path: '/',
    component: Layout,
    redirect: '/dashboard',
    children: [
      {
    
    
        path: 'dashboard',
        name: 'Dashboard',
        component: () => import('@/views/dashboard/index'),
        meta: {
    
     title: 'Dashboard', icon: 'dashboard' }
      }
    ]
  },


  {
    
    
    path: '/system',
    component: Layout,
    meta: {
    
    
      title: '系统管理',
      icon: 'el-icon-s-tools'
    },
    alwaysShow: true,
    children: [
      {
    
    
        path: 'sysRole',
        component: () => import('@/views/system/sysRole/list'),
        meta: {
    
    
          title: '角色管理',
          icon: 'el-icon-s-help'
        },
      }
    ]
  },
  // 404 page must be placed at the end !!!
  {
    
     path: '*', redirect: '/404', hidden: true }
]

2. Create vue components

Create the following folders and files under the src/views folder

Create folder: system/sysRole

Create a file: list.vue

<template>
  <div class="app-container">
    角色列表
  </div>
</template>

3. Define APIs

Create the file src/api/system/sysRole.js

/*
角色管理相关的API请求函数
*/
import request from '@/utils/request'

const api_name = '/admin/system/sysRole'

export default {
    
    

  /*
  获取角色分页列表(带搜索)
  */
  getPageList(page, limit, searchObj) {
    
    
    return request({
    
    
      url: `${
      
      api_name}/${
      
      page}/${
      
      limit}`,
      method: 'get',
        // 如果是普通对象参数写法 params: 对象
      // 如果是Json格式,data: 对象
      params: searchObj
    })
  }
}

4. Initialize the vue component

src/views/system/sysRole/list.vue

<template>
  <div class="app-container">
    角色列表
  </div>
</template>
<script>
import api from '@/api/system/sysRole'
export default {
  // 定义数据模型
  data() {
    return {
    }
  },
  // 页面渲染成功后获取数据
  created() {
    this.fetchData()
  },
  // 定义方法
  methods: {
    fetchData() {
    }
  }
}
</script>

5. Define data

  // 定义数据模型
  data() {
    
    
    return {
    
    
      list: [], // 列表
      total: 0, // 总记录数
      page: 1, // 页码
      limit: 10, // 每页记录数
      searchObj: {
    
    }, // 查询条件
      multipleSelection: []// 批量删除选中的记录列表
    }
  },

6. Define methods

  methods: {
    
    
    fetchData(current=1) {
    
    
      this.page = current
      // 调用api
      api.getPageList(this.page, this.limit, this.searchObj).then(response => {
    
    
        this.list = response.data.records
        this.total = response.data.total
      })
    },
  }

7. Form rendering

<div class="app-container">
    <!-- 表格 -->
    <el-table
      v-loading="listLoading"
      :data="list"
      stripe
      border
      style="width: 100%;margin-top: 10px;"
      @selection-change="handleSelectionChange">

      <el-table-column type="selection"/>

      <el-table-column
        label="序号"
        width="70"
        align="center">
        <template slot-scope="scope">
          {
   
   { (page - 1) * limit + scope.$index + 1 }}
        </template>
      </el-table-column>

      <el-table-column prop="roleName" label="角色名称" />
      <el-table-column prop="roleCode" label="角色编码" />
      <el-table-column prop="createTime" label="创建时间" width="160"/>
      <el-table-column label="操作" width="200" align="center">
        <template slot-scope="scope">
          <el-button type="primary" icon="el-icon-edit" size="mini" @click="edit(scope.row.id)" title="修改"/>
          <el-button type="danger" icon="el-icon-delete" size="mini" @click="removeDataById(scope.row.id)" title="删除"/>
        </template>
      </el-table-column>
    </el-table>
  </div>

8. Paging component

<!-- 分页组件 -->
<el-pagination
    :current-page="page"
    :total="total"
    :page-size="limit"
    style="padding: 30px 0; text-align: center;"
    layout="total, prev, pager, next, jumper"
    @current-change="fetchData"
/>

9. Top query form

<!--查询表单-->
<div class="search-div">
      <el-form label-width="70px" size="small">
        <el-row>
          <el-col :span="24">
            <el-form-item label="角色名称">
              <el-input style="width: 100%" v-model="searchObj.roleName" placeholder="角色名称"></el-input>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row style="display:flex">
          <el-button type="primary" icon="el-icon-search" size="mini" :loading="loading" @click="fetchData()">搜索</el-button>
          <el-button icon="el-icon-refresh" size="mini" @click="resetData">重置</el-button>
        </el-row>
      </el-form>
    </div>

Paging and Clearing Methods

// 重置表单
resetData() {
    
    
    console.log('重置查询表单')
    this.searchObj = {
    
    }
    this.fetchData()
}

3. Delete the role

1. Define api

src/api/system/sysRole.js

removeById(id) {
    
    
  return request({
    
    
    url: `${
      
      api_name}/remove/${
      
      id}`,
    method: 'delete'
  })
}

2. Define methods

src/views/system/sysRole/list.vue

Use the MessageBox pop-up component

// 根据id删除数据
removeDataById(id) {
    
    
    // debugger
    this.$confirm('此操作将永久删除该记录, 是否继续?', '提示', {
    
    
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
    }).then(() => {
    
     // promise
        // 点击确定,远程调用ajax
        return api.removeById(id)
    }).then((response) => {
    
    
        this.fetchData(this.page)
        this.$message.success(response.message || '删除成功')
    })
}

4. Add roles

1. Define api

src/api/system/sysRole.js

save(role) {
    
    
  return request({
    
    
    url: `${
      
      api_name}/save`,
    method: 'post',
    data: role
  })
}

2. Define data

export default {
    
    
  // 定义数据模型
  data() {
    
    
    return {
    
    
      list: [], // 讲师列表
      total: 0, // 总记录数
      page: 1, // 页码
      limit: 10, // 每页记录数
      searchObj: {
    
    }, // 查询条件
      multipleSelection: [],// 批量删除选中的记录列表

      dialogVisible: false,
      sysRole: {
    
    },
      saveBtnDisabled: false
    }
  },
  ...
}

3. Define the add button

src/views/system/sysRole/list.vue

Add button to form

<!-- 工具条 -->
<div class="tools-div">
  <el-button type="success" icon="el-icon-plus" size="mini" @click="add">添 加</el-button>
</div>

4. Define the pop-up layer

src/views/system/sysRole/list.vue

Add a popup layer at the bottom of the table

<el-dialog title="添加/修改" :visible.sync="dialogVisible" width="40%" >
      <el-form ref="dataForm" :model="sysRole" label-width="150px" size="small" style="padding-right: 40px;">
        <el-form-item label="角色名称">
          <el-input v-model="sysRole.roleName"/>
        </el-form-item>
        <el-form-item label="角色编码">
          <el-input v-model="sysRole.roleCode"/>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false" size="small" icon="el-icon-refresh-right">取 消</el-button>
        <el-button type="primary" icon="el-icon-check" @click="saveOrUpdate()" size="small">确 定</el-button>
      </span>
    </el-dialog>

5. Realize the function

add(){
    
    
  this.dialogVisible = true
},

saveOrUpdate() {
    
    
  this.saveBtnDisabled = true // 防止表单重复提交
  if (!this.sysRole.id) {
    
    
    this.saveData()
  } else {
    
    
    this.updateData()
  }
},

// 新增
saveData() {
    
    
  api.save(this.sysRole).then(response => {
    
    
    this.$message.success(response.message || '操作成功')
    this.dialogVisible = false
    this.fetchData(this.page)
  })
}

5. Role modification and data echo

1. Define api

src/api/system/sysRole.js

getById(id) {
    
    
  return request({
    
    
    url: `${
      
      api_name}/get/${
      
      id}`,
    method: 'get'
  })
},

updateById(role) {
    
    
  return request({
    
    
    url: `${
      
      api_name}/update`,
    method: 'put',
    data: role
  })
}

2. Call the api in the component

methods define fetchDataById

edit(id) {
    
    
  this.dialogVisible = true
  this.fetchDataById(id)
},

fetchDataById(id) {
    
    
  api.getById(id).then(response => {
    
    
    this.sysRole = response.data
  })
}

3. Modify and submit

updateData() {
    
    
  api.updateById(this.sysRole).then(response => {
    
    
    this.$message.success(response.message || '操作成功')
    this.dialogVisible = false
    this.fetchData(this.page)
  })
}

6. Batch delete

1. Define api

src/api/system/sysRole.js

batchRemove(idList) {
    
    
  return request({
    
    
    url: `${
      
      api_name}/batchRemove`,
    method: `delete`,
    data: idList
  })
},

2. Initialize components

src/views/system/sysRole/list.vue

Add batch delete button on table component

<!-- 工具条 -->
<div class="tools-div">
  <el-button type="success" icon="el-icon-plus" size="mini" @click="add">添 加</el-button>
  <el-button class="btn-add" size="mini" @click="batchRemove()" >批量删除</el-button>
</div>

Add checkbox to table component

<el-table
  v-loading="listLoading"
  :data="list"
  stripe
  border
  style="width: 100%;margin-top: 10px;"
  @selection-change="handleSelectionChange">
  <el-table-column type="selection"/>

3. Realize the function

data defines data

multipleSelection: []// 批量删除选中的记录列表

perfect method

// 当多选选项发生变化的时候调用
handleSelectionChange(selection) {
    
    
  console.log(selection)
  this.multipleSelection = selection
},
// 批量删除
batchRemove() {
    
    
  if (this.multipleSelection.length === 0) {
    
    
    this.$message.warning('请选择要删除的记录!')
    return
  }
  this.$confirm('此操作将永久删除该记录, 是否继续?', '提示', {
    
    
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  }).then(() => {
    
    
    // 点击确定,远程调用ajax
    // 遍历selection,将id取出放入id列表
    var idList = []
    this.multipleSelection.forEach(item => {
    
    
      idList.push(item.id)
    })
    // 调用api
    return api.batchRemove(idList)
  }).then((response) => {
    
    
    this.fetchData()
    this.$message.success(response.message)
  })
}

Guess you like

Origin blog.csdn.net/AN_NI_112/article/details/131420179