Browse Source

权限管理,员工管理

ysc 1 year ago
parent
commit
c5883f20ae
4 changed files with 553 additions and 148 deletions
  1. 18 0
      src/api/system/role.js
  2. 75 112
      src/views/system/components/dept.vue
  3. 450 0
      src/views/system/permission.vue
  4. 10 36
      src/views/system/user.vue

+ 18 - 0
src/api/system/role.js

@@ -117,3 +117,21 @@ export function deptTreeSelect(roleId) {
     method: 'get'
   })
 }
+
+
+// 根据角色ID查询用户ID
+export function getUserIdsByRoleId(roleId) {
+  return request({
+    url: '/system/role/getUserIdsByRoleId/' + roleId,
+    method: 'get'
+  })
+}
+
+// 根据角色ID查询用户ID
+export function saveRoleUser(data) {
+  return request({
+    url: '/system/role/saveRoleUser',
+    method: 'post',
+    data: data
+  })
+}

+ 75 - 112
src/views/system/dept.vue → src/views/system/components/dept.vue

@@ -1,100 +1,40 @@
 <template>
-  <div class="app-container">
-    <el-form :model="queryParams" ref="queryForm" size="mini" :inline="true">
-      <el-form-item label="部门名称" prop="deptName">
-        <el-input
-          v-model="queryParams.deptName"
-          placeholder="请输入部门名称"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="状态" prop="status">
-        <el-select v-model="queryParams.status" placeholder="部门状态" clearable>
-          <el-option :key="0" label="正常" :value="0"/>
-          <el-option :key="1" label="停用" :value="1"/>
-        </el-select>
-      </el-form-item>
-      <el-form-item>
-        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
-        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
-      </el-form-item>
-    </el-form>
+  <div>
+    <div class="head-container">
+      <el-button size="mini" type="primary" @click="handleAdd">新增</el-button>
 
-    <el-row :gutter="10" class="mb8">
-      <el-col :span="1.5">
-        <el-button
-          type="primary"
-          plain
-          icon="el-icon-plus"
-          size="mini"
-          @click="handleAdd"
-          v-hasPermi="['system:dept:add']"
-        >新增
-        </el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="info"
-          plain
-          icon="el-icon-sort"
-          size="mini"
-          @click="toggleExpandAll"
-        >展开/折叠
-        </el-button>
-      </el-col>
-    </el-row>
-
-    <el-table
-      v-if="refreshTable"
-      :data="deptList"
-      row-key="id"
-      size="mini"
-      :default-expand-all="isExpandAll"
-      :tree-props="{children: 'children', hasChildren: 'hasChildren'}">
-      <el-table-column prop="deptName" label="部门名称" width="260"></el-table-column>
-      <el-table-column prop="orderNum" label="排序" width="200"></el-table-column>
-      <el-table-column prop="status" label="状态" width="100">
-        <template slot-scope="scope">
-          <el-tag type="success" size="small" v-if="scope.row.status==0">正常</el-tag>
-          <el-tag type="info" size="small" v-else>停用</el-tag>
-        </template>
-      </el-table-column>
-      <el-table-column label="创建时间" align="center" prop="createTime" width="200">
-        <template slot-scope="scope">
-          <span>{{ parseTime(scope.row.createTime) }}</span>
-        </template>
-      </el-table-column>
-      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
-        <template slot-scope="scope">
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-edit"
-            @click="handleUpdate(scope.row)"
-            v-hasPermi="['system:dept:edit']"
-          >修改
-          </el-button>
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-plus"
-            @click="handleAdd(scope.row)"
-            v-hasPermi="['system:dept:add']"
-          >新增
-          </el-button>
-          <el-button
-            v-if="scope.row.parentId != 0"
-            size="mini"
-            type="text"
-            icon="el-icon-delete"
-            @click="handleDelete(scope.row)"
-            v-hasPermi="['system:dept:delete']"
-          >删除
-          </el-button>
-        </template>
-      </el-table-column>
-    </el-table>
+      <el-input
+        v-model="deptName"
+        placeholder="请输入部门名称"
+        clearable
+        size="mini"
+        prefix-icon="el-icon-search"
+        style="margin-left: 20px"/>
+    </div>
+    <div class="head-container">
+      <el-tree
+        :data="deptData"
+        :props="defaultProps"
+        :expand-on-click-node="false"
+        :filter-node-method="filterNode"
+        ref="deptTree"
+        node-key="id"
+        default-expand-all
+        highlight-current
+        @node-click="handleNodeClick">
+            <span class="custom-tree-node" slot-scope="{ node, data }">
+              <span>{{ node.label }}</span>
+              <el-popover
+                placement="right"
+                trigger="hover">
+                <el-button size="mini" type="primary" @click="handleAdd(data)">新增</el-button>
+                <el-button size="mini" @click="handleUpdate(data)">修改</el-button>
+                <el-button size="mini" type="danger">删除</el-button>
+                <i class="el-icon-share" slot="reference"></i>
+               </el-popover>
+            </span>
+      </el-tree>
+    </div>
 
     <!-- 添加或修改部门对话框 -->
     <el-dialog :title="title" :visible.sync="open" width="600px" append-to-body :close-on-click-modal="false">
@@ -158,6 +98,7 @@
 import {listDept, getDept, delDept, addDept, updateDept, listDeptExcludeChild} from "@/api/system/dept";
 import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+import {deptTreeSelect} from "@/api/system/user";
 
 export default {
   name: "Dept",
@@ -165,22 +106,17 @@ export default {
 
   data() {
     return {
-      // 表格树数据
-      deptList: [],
+      deptName: '',
+      deptData:[],
       // 部门树选项
       deptOptions: [],
       // 弹出层标题
       title: "",
       // 是否显示弹出层
       open: false,
-      // 是否展开,默认全部展开
-      isExpandAll: true,
-      // 重新渲染表格状态
-      refreshTable: true,
-      // 查询参数
-      queryParams: {
-        deptName: undefined,
-        status: undefined
+      defaultProps: {
+        children: "children",
+        label: "name"
       },
       // 表单参数
       form: {},
@@ -212,18 +148,30 @@ export default {
       }
     };
   },
+  watch: {
+    deptName(val) {
+      this.$refs.deptTree.filter(val);
+    }
+  },
   created() {
-    this.getList();
+    this.getDeptTree();
   },
   methods: {
-    /** 查询部门列表 */
-    getList() {
-      this.loading = true;
-      listDept(this.queryParams).then(response => {
-        this.deptList = this.handleTree(response.data, "id");
-        this.loading = false;
+    /** 查询部门下拉树结构 */
+    getDeptTree() {
+      deptTreeSelect().then(response => {
+        this.deptData = response.data;
       });
     },
+    /** 筛选节点 */
+    filterNode(value, data) {
+      if (!value) return true;
+      return data.name.indexOf(value) !== -1;
+    },
+    /** 节点单击事件 */
+    handleNodeClick(data) {
+      this.$emit('selectDept', data.id)
+    },
 
     // 取消按钮
     cancel() {
@@ -335,4 +283,19 @@ export default {
 .el-form-item--mini.el-form-item, .el-form-item--small.el-form-item {
   margin-bottom: 10px;
 }
+
+.head-container {
+  display: flex;
+  margin-bottom: 20px;
+  justify-content: space-between;
+}
+
+.custom-tree-node {
+  flex: 1;
+  display: flex;
+  align-items: center;
+  font-size: 14px;
+  padding-right: 8px;
+}
 </style>
+

+ 450 - 0
src/views/system/permission.vue

@@ -0,0 +1,450 @@
+<template>
+  <div class="app-container">
+    <el-row :gutter="20">
+      <el-col :span="8">
+        <el-card style="height:calc(100vh - 90px)">
+          <div class="head-container">
+            <el-button size="mini" type="primary" @click="handleAdd">新增</el-button>
+
+            <el-input
+              v-model="roleName"
+              placeholder="请输入角色名称"
+              clearable
+              size="mini"
+              prefix-icon="el-icon-search"
+              style="margin-left: 20px"/>
+          </div>
+
+          <el-table :data="roleFilterList" size="mini" @row-click="rowClick" :row-style="rowStyle">
+            <el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true"/>
+            <!--          <el-table-column label="权限字符" prop="roleKey" :show-overflow-tooltip="true"/>-->
+            <el-table-column label="状态" align="center">
+              <template slot-scope="scope">
+                <el-switch
+                  v-model="scope.row.status"
+                  active-value="0"
+                  inactive-value="1"
+                  @change="handleStatusChange(scope.row)"
+                ></el-switch>
+              </template>
+            </el-table-column>
+            <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="130">
+              <template slot-scope="scope" v-if="scope.row.id !== 1">
+                <el-button
+                  size="mini"
+                  type="text"
+                  icon="el-icon-edit"
+                  @click="handleUpdate(scope.row)"
+                  v-hasPermi="['system:role:edit']"
+                >修改
+                </el-button>
+                <el-button
+                  size="mini"
+                  type="text"
+                  icon="el-icon-delete"
+                  @click="handleDelete(scope.row)"
+                  v-hasPermi="['system:role:delete']"
+                >删除
+                </el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-card>
+
+      </el-col>
+
+      <el-col :span="8">
+        <el-card style="height:calc(100vh - 90px)">
+          <div class="head-container">
+            <div style="font-size: 18px">菜单权限</div>
+            <el-button size="mini" type="primary" @click="saveRoleMenus">保存</el-button>
+          </div>
+          <el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand">展开/折叠</el-checkbox>
+          <el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll">全选/全不选</el-checkbox>
+          <el-checkbox v-model="menuCheckStrictly" @change="handleCheckedTreeConnect">父子联动</el-checkbox>
+          <div style="height:calc(100vh - 200px);overflow: auto">
+            <el-tree
+              class="tree-border"
+              :data="menuOptions"
+              show-checkbox
+              ref="menuTree"
+              node-key="id"
+              :check-strictly="!menuCheckStrictly"
+              empty-text="加载中,请稍候"
+              :props="defaultProps"
+            ></el-tree>
+          </div>
+        </el-card>
+      </el-col>
+
+      <el-col :span="8">
+        <el-card style="height:calc(100vh - 90px)">
+          <div class="head-container">
+            <el-input
+              v-model="userName"
+              placeholder="请输入名字进行过滤"
+              clearable
+              size="mini"
+              prefix-icon="el-icon-search"
+              style="margin-right: 20px"/>
+
+            <el-button size="mini" type="primary" @click="saveRoleUser">保存</el-button>
+          </div>
+          <div style="height:calc(100vh - 180px);overflow: auto">
+            <el-tree
+              class="tree-border"
+              ref="userTree"
+              :data="userList"
+              node-key="id"
+              show-checkbox
+              :props="{label:'name'}"
+              :default-expand-all="true"
+              :filter-node-method="filterNode">
+            </el-tree>
+          </div>
+        </el-card>
+      </el-col>
+    </el-row>
+
+    <!-- 添加或修改角色配置对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body :close-on-click-modal="false">
+      <el-form ref="form" :model="form" :rules="rules" size="mini" label-width="100px">
+        <el-form-item label="角色名称" prop="roleName">
+          <el-input v-model="form.roleName" placeholder="请输入角色名称"/>
+        </el-form-item>
+        <el-form-item prop="roleKey">
+          <span slot="label">
+            <el-tooltip content="控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasRole('admin')`)" placement="top">
+              <i class="el-icon-question"></i>
+            </el-tooltip>
+            权限字符
+          </span>
+          <el-input v-model="form.roleKey" placeholder="请输入权限字符"/>
+        </el-form-item>
+        <el-form-item label="角色顺序" prop="roleSort">
+          <el-input-number v-model="form.roleSort" controls-position="right" :min="0"/>
+        </el-form-item>
+        <el-form-item label="状态" prop="status">
+          <el-radio-group v-model="form.status">
+            <el-radio label="0">正常</el-radio>
+            <el-radio label="1">停用</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" size="mini" @click="submitForm">确 定</el-button>
+        <el-button size="mini" @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+  </div>
+</template>
+
+<script>
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+
+import {getDeptUserTree} from '@/api/system/user'
+import {roleMenuTreeselect, treeselect as menuTreeselect} from "@/api/system/menu";
+import {addRole, delRole, getRole, getUserIdsByRoleId, listRole, saveRoleUser, updateRole} from "@/api/system/role";
+
+
+export default {
+  name: "Dept",
+  components: {Treeselect},
+
+  data() {
+    return {
+      roleName: '',
+      roleList: [],
+      roleFilterList: [],
+      selectedRow: null,
+      menuExpand: false,
+      menuNodeAll: false,
+      menuCheckStrictly: true,
+      // 菜单列表
+      menuOptions: [],
+      defaultProps: {
+        children: "children",
+        label: "menuName"
+      },
+      userName: null,
+      // 用户列表
+      userList: [],
+
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        roleName: [
+          {required: true, message: "角色名称不能为空", trigger: "blur"}
+        ],
+        roleKey: [
+          {required: true, message: "权限字符不能为空", trigger: "blur"}
+        ],
+        roleSort: [
+          {required: true, message: "角色顺序不能为空", trigger: "blur"}
+        ]
+      }
+    };
+  },
+  watch: {
+    userName(val) {
+      this.$refs.userTree.filter(val);
+    },
+    roleName(val) {
+      if (!val) {
+        this.roleFilterList = this.roleList
+      }
+      this.roleFilterList = this.roleList.filter(item => item.roleName.indexOf(val) > -1)
+    }
+  },
+  created() {
+    this.initData();
+  },
+  methods: {
+    initData() {
+      this.getRoleList();
+      this.getMenuTreeSelect();
+      this.getDeptUserTrees();
+    },
+
+    /** 查询角色列表 */
+    getRoleList() {
+      listRole({}).then(response => {
+          this.roleList = response.data;
+          this.roleFilterList = this.roleList
+        }
+      );
+    },
+
+    /** 表单重置 */
+    reset() {
+      this.form = {
+        id: undefined,
+        roleName: undefined,
+        roleKey: undefined,
+        roleSort: 0,
+        status: "0",
+        menuIds: [],
+        deptIds: [],
+        menuCheckStrictly: true,
+        deptCheckStrictly: true,
+        remark: undefined
+      };
+      this.resetForm("form");
+    },
+
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加角色";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getRole(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改角色";
+      });
+    },
+
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != undefined) {
+            updateRole(this.form).then(response => {
+              this.$message.success("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addRole(this.form).then(response => {
+              this.$message.success("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 取消按钮 */
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    /** 角色状态修改 */
+    handleStatusChange(row) {
+      let text = row.status === "0" ? "启用" : "停用";
+      this.$confirm('确认要"' + text + '""' + row.roleName + '"角色吗?').then(function () {
+        return changeStatus(row.id, row.status);
+      }).then(() => {
+        this.$message.success(text + "成功");
+      }).catch(function () {
+        row.status = row.status === "0" ? "1" : "0";
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除角色编号为"' + ids + '"的数据项?').then(() => {
+        return delRole(ids);
+      }).then(() => {
+        this.getList();
+        this.$message.success("删除成功");
+      }).catch(() => {
+      });
+    },
+
+    rowClick(row, column, event) {
+      if (column.label === '操作') {
+        return
+      }
+      this.selectedRow = row.id
+      this.setRoleMenuTreeSelect(row.id)
+      this.setRoleUserTreeSelect(row.id)
+    },
+    rowStyle({row, rowIndex}) {
+      if (row.id === this.selectedRow) {
+        return {
+          background: '#DCDFE6'
+        }
+      }
+    },
+
+    /** 查询菜单树结构 */
+    getMenuTreeSelect() {
+      menuTreeselect().then(res => {
+        this.menuOptions = res.data;
+      });
+    },
+
+    /** 根据角色ID查询菜单树结构 */
+    setRoleMenuTreeSelect(id) {
+      roleMenuTreeselect(id).then(res => {
+        let checkedKeys = this.$refs.menuTree.getCheckedKeys();
+        checkedKeys.forEach((v) => {
+          this.$nextTick(() => {
+            this.$refs.menuTree.setChecked(v, false, false);
+          })
+        })
+
+        let data = res.data.checkedKeys
+        data.forEach((v) => {
+          this.$nextTick(() => {
+            this.$refs.menuTree.setChecked(v, true, false);
+          })
+        })
+
+      });
+    },
+
+    /** 保存角色权限 */
+    saveRoleMenus() {
+      if (!this.selectedRow) {
+        return
+      }
+      // 目前被选中的菜单节点
+      let checkedKeys = this.$refs.menuTree.getCheckedKeys();
+      // 半选中的菜单节点
+      let halfCheckedKeys = this.$refs.menuTree.getHalfCheckedKeys();
+      checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
+      let data = {
+        id: this.selectedRow,
+        menuIds: checkedKeys
+      }
+      updateRole(data).then(response => {
+        this.$message.success("保存成功");
+      });
+    },
+
+    // 树权限(展开/折叠)
+    handleCheckedTreeExpand(value) {
+      let treeList = this.menuOptions;
+      for (let i = 0; i < treeList.length; i++) {
+        this.$refs.menuTree.store.nodesMap[treeList[i].id].expanded = value;
+      }
+    },
+    // 树权限(全选/全不选)
+    handleCheckedTreeNodeAll(value) {
+      this.$refs.menuTree.setCheckedNodes(value ? this.menuOptions : []);
+    },
+    // 树权限(父子联动)
+    handleCheckedTreeConnect(value) {
+      this.menuCheckStrictly = value ? true : false;
+    },
+
+    filterNode(value, data) {
+      if (!value) return true;
+      return data.name.indexOf(value) !== -1;
+    },
+
+    getDeptUserTrees() {
+      getDeptUserTree('').then(res => {
+        this.userList = res.data
+      });
+    },
+
+    setRoleUserTreeSelect(id) {
+      getUserIdsByRoleId(id).then(res => {
+        let checkedKeys = this.$refs.userTree.getCheckedKeys();
+        checkedKeys.forEach((v) => {
+          this.$nextTick(() => {
+            this.$refs.userTree.setChecked(v, false, false);
+          })
+        })
+
+        res.data.forEach((v) => {
+          this.$nextTick(() => {
+            this.$refs.userTree.setChecked(v, true, false);
+          })
+        })
+      })
+    },
+
+    /** 保存角色用户 */
+    saveRoleUser() {
+      if (!this.selectedRow) {
+        return
+      }
+      // 目前被选中的人员节点
+      let checkedKeys = this.$refs.userTree.getCheckedKeys();
+      // 半选中的人员节点
+      let halfCheckedKeys = this.$refs.userTree.getHalfCheckedKeys();
+      checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
+      let data = {
+        roleId: this.selectedRow,
+        userIds: checkedKeys
+      }
+      saveRoleUser(data).then(res => {
+        this.$message.success("保存成功");
+
+      })
+    }
+
+
+  }
+};
+</script>
+<style scoped lang="scss">
+.head-container {
+  display: flex;
+  margin-bottom: 20px;
+  justify-content: space-between;
+}
+
+.el-form-item--mini.el-form-item, .el-form-item--small.el-form-item {
+  margin-bottom: 10px;
+}
+</style>

+ 10 - 36
src/views/system/user.vue

@@ -3,29 +3,7 @@
     <el-row :gutter="20">
       <!--部门数据-->
       <el-col :span="5" :xs="24">
-        <div class="head-container">
-          <el-input
-            v-model="deptName"
-            placeholder="请输入部门名称"
-            clearable
-            size="mini"
-            prefix-icon="el-icon-search"
-            style="margin-bottom: 20px"
-          />
-        </div>
-        <div class="head-container">
-          <el-tree
-            :data="deptOptions"
-            :props="defaultProps"
-            :expand-on-click-node="false"
-            :filter-node-method="filterNode"
-            ref="tree"
-            node-key="id"
-            default-expand-all
-            highlight-current
-            @node-click="handleNodeClick"
-          />
-        </div>
+        <dept @selectDept="deptSelect"></dept>
       </el-col>
       <!--用户数据-->
       <el-col :span="19" :xs="24">
@@ -255,13 +233,15 @@ import {
   changeUserStatus,
   deptTreeSelect
 } from "@/api/system/user";
-import {getToken} from "@/utils/auth";
+
+import Dept from './components/dept'
+
 import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
 
 export default {
   name: "User",
-  components: {Treeselect},
+  components: {Dept, Treeselect},
   data() {
     return {
       // 总条数
@@ -283,10 +263,7 @@ export default {
       roleOptions: [],
       // 表单参数
       form: {},
-      defaultProps: {
-        children: "children",
-        label: "name"
-      },
+
       // 查询参数
       queryParams: {
         pageNum: 1,
@@ -349,14 +326,9 @@ export default {
         this.deptOptions = response.data;
       });
     },
-    // 筛选节点
-    filterNode(value, data) {
-      if (!value) return true;
-      return data.label.indexOf(value) !== -1;
-    },
     // 节点单击事件
-    handleNodeClick(data) {
-      this.queryParams.deptId = data.id;
+    deptSelect(data) {
+      this.queryParams.deptId = data;
       this.handleQuery();
     },
     // 用户状态修改
@@ -505,7 +477,9 @@ export default {
 </script>
 
 <style scoped lang="scss">
+
 .el-form-item--mini.el-form-item, .el-form-item--small.el-form-item {
   margin-bottom: 10px;
 }
+
 </style>