绑定完请刷新页面
取消
刷新

分享好友

×
取消 复制
Spring Security(六):前端菜单,角色权限页面的搭建
2023-07-04 15:31:10

目前项目中做了几个有关权限控制的页面,主要做了三个,角色管理,资源管理,角色权限的页面。

角色管理

该页面主要是对角色的crud,这个比较简单就不多讲了。

资源管理

这个页面其实是对菜单的配置,也就是路由的设置,我采用了组件复用的思路,就是增加和更新页面用的是同一个组件,启用前判断是增加还是更新就好了。


如果是新增的话有一个会初始化


更新的话就会得到信息,显示出来

Vue代码

  1. 新建src\views\pre\perm\edit.vue文件,这个其实编辑按钮引用的组件,通过这里可以设置我们要进行的操作的是编辑,然后通过scope获取到数据
        <template>
          <div>
            <el-button size="mini" type="success" @click="to">编辑</el-button>
            <eForm ref="form" :menus="menus" :sup_this="sup_this" :is-add="false"/>
          </div>
        </template>
        <script>
        import eForm from './form'
        export default {
          components: { eForm },
          props: {
            data: {
              type: Object,
              required: true
            },
            sup_this: {
              type: Object,
              required: true
            },
            menus: {
              type: Array,
              required: true
            }
          },
          methods: {
            to() {
              const _this = this.$refs.form
              _this.roleIds = []
              _this.form = { per_id: this.data.per_id, per_component: this.data.per_component, per_name: this.data.per_name, per_sort: this.data.per_sort,
                per_parent_id: this.data.per_parent_id, per_resource: this.data.per_resource, per_icon: this.data.per_icon, per_describe: this.data.per_describe }
              _this.dialog = true
            }
          }
        }
        </script>

        <style scoped>
          div{
            display: inline-block;
            margin-right: 3px;
          }
        </style>

2.新建一个src\views\pre\perm\form.vue文件
这个就是我们要复用的组件了

    <template>
      <el-dialog :append-to-body="true" :visible.sync="dialog" :title="isAdd ? '新增菜单' : '编辑菜单'" width="600px">
        <el-form ref="form" :model="form" :rules="rules" size="small" label-width="80px">
          <el-form-item label="菜单图标">
            <el-popover
              placement="bottom-start"
              width="460"
              trigger="click"
              @show="$refs['iconSelect'].reset()">
              <el-input slot="reference" v-model="form.icon" style="width: 460px;" placeholder="点击选择图标" readonly>
                <svg-icon v-if="form.icon" slot="prefix" :icon-class="form.icon" class="el-input__icon" style="height: 32px;width: 16px;" />
                <i v-else slot="prefix" class="el-icon-search el-input__icon"/>
              </el-input>
            </el-popover>
          </el-form-item>
          <el-form-item label="菜单名称" prop="per_name">
            <el-input v-model="form.per_name" placeholder="名称" style="width: 460px;"/>
          </el-form-item>
          <el-form-item label="菜单排序" prop="per_sort">
            <el-input v-model.number="form.per_sort" placeholder="序号越小越靠前" style="width: 460px;"/>
          </el-form-item>
          <el-form-item label="URL地址">
            <el-input v-model="form.per_resource" placeholder="组件路径" style="width: 460px;"/>
          </el-form-item>
          <el-form-item label="组件路径">
            <el-input v-model="form.per_component" placeholder="组件路径" style="width: 460px;"/>
          </el-form-item>
          <el-form-item label="上级菜单">
            <treeselect v-model="form.per_parent_id" :options="menus" style="width: 460px;" placeholder="选择上级类目" />
          </el-form-item>
          <el-form-item label="菜单描述" prop="per_describe">
            <el-input v-model.number="form.per_describe" placeholder="请填写菜单描述" style="width: 460px;"/>
          </el-form-item>
        </el-form>
        <div slot="footer" class="dialog-footer">
          <el-button type="text" @click="cancel">取消</el-button>
          <el-button :loading="loading" type="primary" @click="doSubmit">确认</el-button>
        </div>
      </el-dialog>
    </template>

    <script>
    // import the component
    import Treeselect from '@riophae/vue-treeselect'
    // import the styles
    import '@riophae/vue-treeselect/dist/vue-treeselect.css'
    import { add, edit } from '@/api/menu'
    export default {
      components: { Treeselect },
      props: {
        menus: {
          type: Array,
          required: true
        },
        isAdd: {
          type: Boolean,
          required: true
        },
        sup_this: {
          type: Object,
          default: null
        }
      },
      data() {
        return {
          loading: false, dialog: false,
          form: { per_id: null, per_name: '', per_sort: 999, per_resource: '', per_component: '', per_parent_id: 0, per_icon: '', per_describe: '' },
          roleIds: [],
          rules: {
            per_name: [
              { required: true, message: '请输入名称', trigger: 'blur' }
            ],
            per_sort: [
              { required: true, message: '请输入序号', trigger: 'blur', type: 'number' }
            ]
          }
        }
      },
      methods: {
        cancel() {
          this.resetForm()
        },
        doSubmit() {
          this.$refs['form'].validate((valid) => {
            if (valid) {
              this.loading = true
              this.form.roles = []
              const _this = this
              this.roleIds.forEach(function(data, index) {
                const role = { id: data }
                _this.form.roles.push(role)
              })
              if (this.isAdd) {
                this.doAdd()
              } else this.doEdit()
            } else {
              return false
            }
          })
        },
        doAdd() {
          add(this.form).then(res => {
            this.resetForm()
            this.$notify({
              title: '添加成功',
              type: 'success',
              duration: 2500
            })
            this.loading = false
            this.$parent.$parent.init()
            this.$parent.$parent.getMenus()
          }).catch(error => {
            this.loading = false
            this.$message({
              showClose: true,
              message: error,
              type: 'error'
            })
          })
        },
        doEdit() {
          edit(this.form).then(res => {
            this.resetForm()
            this.$notify({
              title: '修改成功',
              type: 'success',
              duration: 2500
            })
            this.loading = false
            this.sup_this.init()
            this.sup_this.getMenus()
          }).catch(err => {
            this.loading = false
            console.log(err.msg)
          })
        },
        resetForm() {
          this.dialog = false
          this.$refs['form'].resetFields()
          this.form = { name: '', sort: 999, path: '', component: '', iframe: 'false', pid: 0, icon: '' }
          this.roleIds = []
        },
        selected(name) {
          this.form.icon = name
        }
      }
    }
    </script>

    <style scoped>

    </style>

做了这个通用的组件就不用在代码中同时引用两个组件了。

角色权限

我的这个项目前端对权限的控制对象主要是页面的路由,可以动态的去设置角色可以显示哪些菜单。使用了el-tree这个组件…不会css…页面很丑莫见怪…
系统管理员的页面


测试用户,当然正常情况下用户是不应该可以看到这些关于全县的页面的,我这里只是拿来测试。


可以看到测试用户那边的路由页面根据我们的配置就显示出来了

动态配置的思路

角色权限这个页面中的树形组件其实是对我们数据库中的RolePermission组件进行增删改查,大致过程是:

  • 通过角色id获得用户的路由集合,然后通过el-tree组件去渲染是否被选中
  • 更新的思路是首先删除RolePermission表中这个角色id所有的数据,然后根据我们前端拿到的id集合去批量增加。

小问题

由于el-tree组件拿到我们后台给的父节点的id,会直接把子节点全部选中,但是这个明显不符合我们的要求,目前的解决办法是把父子节点的关联移除,这样有个问题是我们自己去配置的时候选中父节点,子节点要一个一个去选择…我还在想解决办法…

分享好友

分享这个小栈给你的朋友们,一起进步吧。

Spring
创建时间:2021-08-11 15:53:20
Spring中国教育管理中心助力Spring认证学员发展
展开
订阅须知

• 所有用户可根据关注领域订阅专区或所有专区

• 付费订阅:虚拟交易,一经交易不退款;若特殊情况,可3日内客服咨询

• 专区发布评论属默认订阅所评论专区(除付费小栈外)

栈主、嘉宾

查看更多
  • Talent skills
    栈主

小栈成员

查看更多
  • 你见吾家
  • LCR_
  • ZHANGSHANGs
  • he9281
戳我,来吐槽~