permission.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. <template>
  2. <div class="app-container">
  3. <div style="font-size:13px;color:#A8A8A8;text-align: center;margin-bottom: 10px">
  4. <i class="el-icon-info"/>单击左边列表某一行选中角色,中部展示角色对应的菜单按钮权限,右边展示具有此角色的用户,可以对菜单按钮和用户进行增删
  5. </div>
  6. <el-row :gutter="20">
  7. <el-col :span="8">
  8. <el-card style="height:calc(100vh - 115px)">
  9. <div class="head-container">
  10. <el-button size="mini" type="primary" @click="handleAdd">新增</el-button>
  11. <el-input
  12. v-model="roleName"
  13. placeholder="请输入角色名称"
  14. clearable
  15. size="mini"
  16. prefix-icon="el-icon-search"
  17. style="margin-left: 20px"/>
  18. </div>
  19. <el-table :data="roleFilterList" size="mini" @row-click="rowClick" :row-style="rowStyle">
  20. <el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true"/>
  21. <!-- <el-table-column label="权限字符" prop="roleKey" :show-overflow-tooltip="true"/>-->
  22. <el-table-column label="状态" align="center">
  23. <template slot-scope="scope">
  24. <el-switch
  25. v-model="scope.row.status"
  26. active-value="0"
  27. inactive-value="1"
  28. @change="handleStatusChange(scope.row)"
  29. ></el-switch>
  30. </template>
  31. </el-table-column>
  32. <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="130">
  33. <template slot-scope="scope" v-if="scope.row.id !== 1">
  34. <el-button
  35. size="mini"
  36. type="text"
  37. icon="el-icon-edit"
  38. @click="handleUpdate(scope.row)"
  39. v-hasPermi="['system:role:edit']"
  40. >修改
  41. </el-button>
  42. <el-button
  43. size="mini"
  44. type="text"
  45. icon="el-icon-delete"
  46. @click="handleDelete(scope.row)"
  47. v-hasPermi="['system:role:delete']"
  48. >删除
  49. </el-button>
  50. </template>
  51. </el-table-column>
  52. </el-table>
  53. </el-card>
  54. </el-col>
  55. <el-col :span="8">
  56. <el-card style="height:calc(100vh - 115px)">
  57. <div class="head-container">
  58. <div style="font-size: 18px">菜单权限</div>
  59. <el-button size="mini" type="primary" @click="saveRoleMenus">保存</el-button>
  60. </div>
  61. <el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand">展开/折叠</el-checkbox>
  62. <el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll">全选/全不选</el-checkbox>
  63. <el-checkbox v-model="menuCheckStrictly" @change="handleCheckedTreeConnect">父子联动</el-checkbox>
  64. <div style="height:calc(100vh - 200px);overflow: auto">
  65. <el-tree
  66. class="tree-border"
  67. :data="menuOptions"
  68. show-checkbox
  69. ref="menuTree"
  70. node-key="id"
  71. :check-strictly="!menuCheckStrictly"
  72. empty-text="加载中,请稍候"
  73. :props="defaultProps"
  74. ></el-tree>
  75. </div>
  76. </el-card>
  77. </el-col>
  78. <el-col :span="8">
  79. <el-card style="height:calc(100vh - 115px)">
  80. <div class="head-container">
  81. <el-input
  82. v-model="userName"
  83. placeholder="请输入名字进行过滤"
  84. clearable
  85. size="mini"
  86. prefix-icon="el-icon-search"
  87. style="margin-right: 20px"/>
  88. <el-button size="mini" type="primary" @click="saveRoleUser">保存</el-button>
  89. </div>
  90. <div style="height:calc(100vh - 180px);overflow: auto">
  91. <el-tree
  92. class="tree-border"
  93. ref="userTree"
  94. :data="userList"
  95. node-key="id"
  96. show-checkbox
  97. :props="{label:'name'}"
  98. :default-expand-all="true"
  99. :filter-node-method="filterNode">
  100. </el-tree>
  101. </div>
  102. </el-card>
  103. </el-col>
  104. </el-row>
  105. <!-- 添加或修改角色配置对话框 -->
  106. <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body :close-on-click-modal="false">
  107. <el-form ref="form" :model="form" :rules="rules" size="mini" label-width="100px">
  108. <el-form-item label="角色名称" prop="roleName">
  109. <el-input v-model="form.roleName" placeholder="请输入角色名称"/>
  110. </el-form-item>
  111. <el-form-item label="权限字符" prop="roleKey">
  112. <el-input v-model="form.roleKey" placeholder="请输入权限字符"/>
  113. </el-form-item>
  114. <el-form-item label="角色顺序" prop="roleSort">
  115. <el-input-number v-model="form.roleSort" controls-position="right" :min="0"/>
  116. </el-form-item>
  117. <el-form-item label="状态" prop="status">
  118. <el-radio-group v-model="form.status">
  119. <el-radio label="0">正常</el-radio>
  120. <el-radio label="1">停用</el-radio>
  121. </el-radio-group>
  122. </el-form-item>
  123. <el-form-item label="备注" prop="remark">
  124. <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
  125. </el-form-item>
  126. </el-form>
  127. <div slot="footer" class="dialog-footer">
  128. <el-button type="primary" size="mini" @click="submitForm">确 定</el-button>
  129. <el-button size="mini" @click="cancel">取 消</el-button>
  130. </div>
  131. </el-dialog>
  132. </div>
  133. </template>
  134. <script>
  135. import Treeselect from "@riophae/vue-treeselect";
  136. import "@riophae/vue-treeselect/dist/vue-treeselect.css";
  137. import {getDeptUserTree} from '@/api/system/user'
  138. import {roleMenuTreeselect, treeselect as menuTreeselect} from "@/api/system/menu";
  139. import {addRole, delRole, getRole, getUserIdsByRoleId, listRole, saveRoleUser, updateRole} from "@/api/system/role";
  140. export default {
  141. name: "Dept",
  142. components: {Treeselect},
  143. data() {
  144. return {
  145. roleName: '',
  146. roleList: [],
  147. roleFilterList: [],
  148. selectedRow: null,
  149. menuExpand: false,
  150. menuNodeAll: false,
  151. menuCheckStrictly: true,
  152. // 菜单列表
  153. menuOptions: [],
  154. defaultProps: {
  155. children: "children",
  156. label: "menuName"
  157. },
  158. userName: null,
  159. // 用户列表
  160. userList: [],
  161. // 弹出层标题
  162. title: "",
  163. // 是否显示弹出层
  164. open: false,
  165. // 表单参数
  166. form: {},
  167. // 表单校验
  168. rules: {
  169. roleName: [
  170. {required: true, message: "角色名称不能为空", trigger: "blur"}
  171. ],
  172. roleKey: [
  173. {required: true, message: "权限字符不能为空", trigger: "blur"}
  174. ],
  175. roleSort: [
  176. {required: true, message: "角色顺序不能为空", trigger: "change"}
  177. ]
  178. }
  179. };
  180. },
  181. watch: {
  182. userName(val) {
  183. this.$refs.userTree.filter(val);
  184. },
  185. roleName(val) {
  186. if (!val) {
  187. this.roleFilterList = this.roleList
  188. }
  189. this.roleFilterList = this.roleList.filter(item => item.roleName.indexOf(val) > -1)
  190. }
  191. },
  192. created() {
  193. this.initData();
  194. },
  195. methods: {
  196. initData() {
  197. this.getRoleList();
  198. this.getMenuTreeSelect();
  199. this.getDeptUserTrees();
  200. },
  201. /** 查询角色列表 */
  202. getRoleList() {
  203. listRole({}).then(response => {
  204. this.roleList = response.data;
  205. this.roleFilterList = this.roleList
  206. }
  207. );
  208. },
  209. /** 表单重置 */
  210. reset() {
  211. this.form = {
  212. id: undefined,
  213. roleName: undefined,
  214. roleKey: undefined,
  215. roleSort: 0,
  216. status: "0",
  217. menuIds: [],
  218. deptIds: [],
  219. menuCheckStrictly: true,
  220. deptCheckStrictly: true,
  221. remark: undefined
  222. };
  223. this.resetForm("form");
  224. },
  225. /** 新增按钮操作 */
  226. handleAdd() {
  227. this.reset();
  228. this.open = true;
  229. this.title = "添加角色";
  230. },
  231. /** 修改按钮操作 */
  232. handleUpdate(row) {
  233. this.reset();
  234. const id = row.id || this.ids
  235. getRole(id).then(response => {
  236. this.form = response.data;
  237. this.open = true;
  238. this.title = "修改角色";
  239. });
  240. },
  241. /** 提交按钮 */
  242. submitForm() {
  243. this.$refs["form"].validate(valid => {
  244. if (valid) {
  245. if (this.form.id != undefined) {
  246. updateRole(this.form).then(response => {
  247. this.$message.success("修改成功");
  248. this.open = false;
  249. this.getRoleList();
  250. });
  251. } else {
  252. addRole(this.form).then(response => {
  253. this.$message.success("新增成功");
  254. this.open = false;
  255. this.getRoleList();
  256. });
  257. }
  258. }
  259. });
  260. },
  261. /** 取消按钮 */
  262. cancel() {
  263. this.open = false;
  264. this.reset();
  265. },
  266. /** 角色状态修改 */
  267. handleStatusChange(row) {
  268. let text = row.status === "0" ? "启用" : "停用";
  269. this.$confirm('确认要"' + text + '""' + row.roleName + '"角色吗?').then(function () {
  270. return changeStatus(row.id, row.status);
  271. }).then(() => {
  272. this.$message.success(text + "成功");
  273. }).catch(function () {
  274. row.status = row.status === "0" ? "1" : "0";
  275. });
  276. },
  277. /** 删除按钮操作 */
  278. handleDelete(row) {
  279. const ids = row.id || this.ids;
  280. this.$confirm('是否确认删除角色编号为"' + ids + '"的数据项?').then(() => {
  281. return delRole(ids);
  282. }).then(() => {
  283. this.getList();
  284. this.$message.success("删除成功");
  285. }).catch(() => {
  286. });
  287. },
  288. rowClick(row, column, event) {
  289. if (column.label === '操作') {
  290. return
  291. }
  292. this.selectedRow = row.id
  293. this.setRoleMenuTreeSelect(row.id)
  294. this.setRoleUserTreeSelect(row.id)
  295. },
  296. rowStyle({row, rowIndex}) {
  297. if (row.id === this.selectedRow) {
  298. return {
  299. background: '#DCDFE6'
  300. }
  301. }
  302. },
  303. /** 查询菜单树结构 */
  304. getMenuTreeSelect() {
  305. menuTreeselect().then(res => {
  306. this.menuOptions = res.data;
  307. });
  308. },
  309. /** 根据角色ID查询菜单树结构 */
  310. setRoleMenuTreeSelect(id) {
  311. roleMenuTreeselect(id).then(res => {
  312. let checkedKeys = this.$refs.menuTree.getCheckedKeys();
  313. checkedKeys.forEach((v) => {
  314. this.$nextTick(() => {
  315. this.$refs.menuTree.setChecked(v, false, false);
  316. })
  317. })
  318. let data = res.data.checkedKeys
  319. data.forEach((v) => {
  320. this.$nextTick(() => {
  321. this.$refs.menuTree.setChecked(v, true, false);
  322. })
  323. })
  324. });
  325. },
  326. /** 保存角色权限 */
  327. saveRoleMenus() {
  328. if (!this.selectedRow) {
  329. this.$message.info('请先选择角色')
  330. return
  331. }
  332. // 目前被选中的菜单节点
  333. let checkedKeys = this.$refs.menuTree.getCheckedKeys();
  334. // 半选中的菜单节点
  335. let halfCheckedKeys = this.$refs.menuTree.getHalfCheckedKeys();
  336. checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
  337. let data = {
  338. id: this.selectedRow,
  339. menuIds: checkedKeys
  340. }
  341. updateRole(data).then(response => {
  342. this.$message.success("保存成功");
  343. });
  344. },
  345. // 树权限(展开/折叠)
  346. handleCheckedTreeExpand(value) {
  347. let treeList = this.menuOptions;
  348. for (let i = 0; i < treeList.length; i++) {
  349. this.$refs.menuTree.store.nodesMap[treeList[i].id].expanded = value;
  350. }
  351. },
  352. // 树权限(全选/全不选)
  353. handleCheckedTreeNodeAll(value) {
  354. this.$refs.menuTree.setCheckedNodes(value ? this.menuOptions : []);
  355. },
  356. // 树权限(父子联动)
  357. handleCheckedTreeConnect(value) {
  358. this.menuCheckStrictly = value ? true : false;
  359. },
  360. filterNode(value, data) {
  361. if (!value) return true;
  362. return data.name.indexOf(value) !== -1;
  363. },
  364. getDeptUserTrees() {
  365. getDeptUserTree('').then(res => {
  366. this.userList = res.data
  367. });
  368. },
  369. setRoleUserTreeSelect(id) {
  370. getUserIdsByRoleId(id).then(res => {
  371. let checkedKeys = this.$refs.userTree.getCheckedKeys();
  372. checkedKeys.forEach((v) => {
  373. this.$nextTick(() => {
  374. this.$refs.userTree.setChecked(v, false, false);
  375. })
  376. })
  377. res.data.forEach((v) => {
  378. this.$nextTick(() => {
  379. this.$refs.userTree.setChecked(v, true, false);
  380. })
  381. })
  382. })
  383. },
  384. /** 保存角色用户 */
  385. saveRoleUser() {
  386. if (!this.selectedRow) {
  387. this.$message.info('请先选择角色')
  388. return
  389. }
  390. // 目前被选中的人员节点
  391. let checkedKeys = this.$refs.userTree.getCheckedKeys();
  392. // 半选中的人员节点
  393. let halfCheckedKeys = this.$refs.userTree.getHalfCheckedKeys();
  394. checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
  395. let data = {
  396. roleId: this.selectedRow,
  397. userIds: checkedKeys
  398. }
  399. saveRoleUser(data).then(res => {
  400. this.$message.success("保存成功");
  401. })
  402. }
  403. }
  404. };
  405. </script>
  406. <style scoped lang="scss">
  407. .head-container {
  408. display: flex;
  409. margin-bottom: 20px;
  410. justify-content: space-between;
  411. }
  412. .el-form-item--mini.el-form-item, .el-form-item--small.el-form-item {
  413. margin-bottom: 10px;
  414. }
  415. </style>