| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- <template>
- <div class="app-container">
- <el-button type="primary" @click="handleAddRole">New Role</el-button>
- <el-table :data="rolesList" style="width: 100%;margin-top:30px;" border>
- <el-table-column align="center" label="Role Key" width="220">
- <template slot-scope="scope">
- {{ scope.row.key }}
- </template>
- </el-table-column>
- <el-table-column align="center" label="Role Name" width="220">
- <template slot-scope="scope">
- {{ scope.row.name }}
- </template>
- </el-table-column>
- <el-table-column align="header-center" label="Description">
- <template slot-scope="scope">
- {{ scope.row.description }}
- </template>
- </el-table-column>
- <el-table-column align="center" label="Operations">
- <template slot-scope="scope">
- <el-button type="primary" size="small" @click="handleEdit(scope)">Edit</el-button>
- <el-button type="danger" size="small" @click="handleDelete(scope)">Delete</el-button>
- </template>
- </el-table-column>
- </el-table>
- <el-dialog :visible.sync="dialogVisible" :title="dialogType==='edit'?'Edit Role':'New Role'">
- <el-form :model="role" label-width="80px" label-position="left">
- <el-form-item label="Name">
- <el-input v-model="role.name" placeholder="Role Name" />
- </el-form-item>
- <el-form-item label="Desc">
- <el-input
- v-model="role.description"
- :autosize="{ minRows: 2, maxRows: 4}"
- type="textarea"
- placeholder="Role Description"
- />
- </el-form-item>
- <el-form-item label="Menus">
- <el-tree
- ref="tree"
- :check-strictly="checkStrictly"
- :data="routesData"
- :props="defaultProps"
- show-checkbox
- node-key="path"
- class="permission-tree"
- />
- </el-form-item>
- </el-form>
- <div style="text-align:right;">
- <el-button type="danger" @click="dialogVisible=false">Cancel</el-button>
- <el-button type="primary" @click="confirmRole">Confirm</el-button>
- </div>
- </el-dialog>
- </div>
- </template>
- <script>
- import path from 'path'
- import { deepClone } from '@/utils'
- import { getRoutes, getRoles, addRole, deleteRole, updateRole } from '@/api/role'
- const defaultRole = {
- key: '',
- name: '',
- description: '',
- routes: []
- }
- export default {
- data() {
- return {
- role: Object.assign({}, defaultRole),
- routes: [],
- rolesList: [],
- dialogVisible: false,
- dialogType: 'new',
- checkStrictly: false,
- defaultProps: {
- children: 'children',
- label: 'title'
- }
- }
- },
- computed: {
- routesData() {
- return this.routes
- }
- },
- created() {
- // Mock: get all routes and roles list from server
- this.getRoutes()
- this.getRoles()
- },
- methods: {
- async getRoutes() {
- const res = await getRoutes()
- this.serviceRoutes = res.data
- this.routes = this.generateRoutes(res.data)
- },
- async getRoles() {
- const res = await getRoles()
- this.rolesList = res.data
- },
- // Reshape the routes structure so that it looks the same as the sidebar
- generateRoutes(routes, basePath = '/') {
- const res = []
- for (let route of routes) {
- // skip some route
- if (route.hidden) { continue }
- const onlyOneShowingChild = this.onlyOneShowingChild(route.children, route)
- if (route.children && onlyOneShowingChild && !route.alwaysShow) {
- route = onlyOneShowingChild
- }
- const data = {
- path: path.resolve(basePath, route.path),
- title: route.meta && route.meta.title
- }
- // recursive child routes
- if (route.children) {
- data.children = this.generateRoutes(route.children, data.path)
- }
- res.push(data)
- }
- return res
- },
- generateArr(routes) {
- let data = []
- routes.forEach(route => {
- data.push(route)
- if (route.children) {
- const temp = this.generateArr(route.children)
- if (temp.length > 0) {
- data = [...data, ...temp]
- }
- }
- })
- return data
- },
- handleAddRole() {
- this.role = Object.assign({}, defaultRole)
- if (this.$refs.tree) {
- this.$refs.tree.setCheckedNodes([])
- }
- this.dialogType = 'new'
- this.dialogVisible = true
- },
- handleEdit(scope) {
- this.dialogType = 'edit'
- this.dialogVisible = true
- this.checkStrictly = true
- this.role = deepClone(scope.row)
- this.$nextTick(() => {
- const routes = this.generateRoutes(this.role.routes)
- this.$refs.tree.setCheckedNodes(this.generateArr(routes))
- // set checked state of a node not affects its father and child nodes
- this.checkStrictly = false
- })
- },
- handleDelete({ $index, row }) {
- this.$confirm('Confirm to remove the role?', 'Warning', {
- confirmButtonText: 'Confirm',
- cancelButtonText: 'Cancel',
- type: 'warning'
- })
- .then(async() => {
- await deleteRole(row.key)
- this.rolesList.splice($index, 1)
- this.$message({
- type: 'success',
- message: 'Delete succed!'
- })
- })
- .catch(err => { console.error(err) })
- },
- generateTree(routes, basePath = '/', checkedKeys) {
- const res = []
- for (const route of routes) {
- const routePath = path.resolve(basePath, route.path)
- // recursive child routes
- if (route.children) {
- route.children = this.generateTree(route.children, routePath, checkedKeys)
- }
- if (checkedKeys.includes(routePath) || (route.children && route.children.length >= 1)) {
- res.push(route)
- }
- }
- return res
- },
- async confirmRole() {
- const isEdit = this.dialogType === 'edit'
- const checkedKeys = this.$refs.tree.getCheckedKeys()
- this.role.routes = this.generateTree(deepClone(this.serviceRoutes), '/', checkedKeys)
- if (isEdit) {
- await updateRole(this.role.key, this.role)
- for (let index = 0; index < this.rolesList.length; index++) {
- if (this.rolesList[index].key === this.role.key) {
- this.rolesList.splice(index, 1, Object.assign({}, this.role))
- break
- }
- }
- } else {
- const { data } = await addRole(this.role)
- this.role.key = data.key
- this.rolesList.push(this.role)
- }
- const { description, key, name } = this.role
- this.dialogVisible = false
- this.$notify({
- title: 'Success',
- dangerouslyUseHTMLString: true,
- message: `
- <div>Role Key: ${key}</div>
- <div>Role Name: ${name}</div>
- <div>Description: ${description}</div>
- `,
- type: 'success'
- })
- },
- // reference: src/view/layout/components/Sidebar/SidebarItem.vue
- onlyOneShowingChild(children = [], parent) {
- let onlyOneChild = null
- const showingChildren = children.filter(item => !item.hidden)
- // When there is only one child route, the child route is displayed by default
- if (showingChildren.length === 1) {
- onlyOneChild = showingChildren[0]
- onlyOneChild.path = path.resolve(parent.path, onlyOneChild.path)
- return onlyOneChild
- }
- // Show parent if there are no child route to display
- if (showingChildren.length === 0) {
- onlyOneChild = { ... parent, path: '', noShowingChildren: true }
- return onlyOneChild
- }
- return false
- }
- }
- }
- </script>
- <style lang="scss" scoped>
- .app-container {
- .roles-table {
- margin-top: 30px;
- }
- .permission-tree {
- margin-bottom: 30px;
- }
- }
- </style>
|