fz-index.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  1. <template>
  2. <div class="app-container">
  3. <el-row class="roleBox">
  4. <el-col :span="24" class="roleCol">
  5. <div class="roleH"></div>
  6. <span>功能权限</span>
  7. </el-col>
  8. <el-col :span="24" class="roleBot">
  9. <el-row :gutter="10" class="mb8">
  10. <el-col :span="1.5">
  11. <el-button type="primary" style="background-color: #2AC1CA;color: #fff;border: none;" plain icon="el-icon-plus"
  12. @click="handleAdd" v-hasPermi="['system:role:add']">新增</el-button>
  13. </el-col>
  14. <el-col :span="1.5">
  15. <el-button type="primary" style="background-color: #FF9639;color: #fff;border: none;" plain icon="el-icon-refresh"
  16. @click="refreshFn" v-hasPermi="['system:role:list']">刷新</el-button>
  17. </el-col>
  18. <el-col :span="1.5">
  19. <el-button type="primary" style="background-color: #3C8DBC;color: #fff;border: none;" plain icon="el-icon-my-export"
  20. @click="handleAdd" v-hasPermi="['system:role:edit']">保存</el-button>
  21. </el-col>
  22. </el-row>
  23. </el-col>
  24. </el-row>
  25. <el-row class="roleCont" style="margin-top: 18px;">
  26. <el-col :span="5" class="searBoxs">
  27. <div class="searBox">
  28. <div class="searInput">
  29. <input type="text" v-model="queryParams.roleName" placeholder="请输入角色">
  30. </div>
  31. <div class="searBtn">
  32. <img src="@/assets/images/icon_sr_ss@2x.png" @click="handleQuery" alt="" class="icon">
  33. </div>
  34. </div>
  35. <div class="searList">
  36. <div class="searItem" v-loading.fullscreen.lock="fullscreenLoading" v-for="item in roleList" @click="searBtnFn(item)" :class="{'active': item.id == roleId}">
  37. {{item.roleName}}
  38. </div>
  39. </div>
  40. <pagination sty v-show="total>0" :total="total" layout="prev, pager, next" :page.sync="queryParams.pageNum"
  41. :limit.sync="queryParams.pageSize" />
  42. </el-col>
  43. <el-col :span="19" class="roleContr">
  44. <div class="roleContrBox">
  45. <el-col :span="7">
  46. <div class="searContLeft">
  47. <el-tree class="tree-border" @node-click="qxList" :data="deptOptions" default-expand-all ref="dept" node-key="id" :props="defaultProps"></el-tree>
  48. </div>
  49. </el-col>
  50. <el-col :span="17">
  51. <div class="searContRight">
  52. <div class="searTitle">
  53. <div class="searName">
  54. 功能
  55. </div>
  56. <div class="searItem" v-for="item in 8">
  57. <el-checkbox :label="'新增'+item"></el-checkbox>
  58. </div>
  59. </div>
  60. <div class="searCont" v-for="items in 12" @click="searIndex = item" :class="{'active': searIndex == item}">
  61. <div class="searName">
  62. 功能功能{{items}}
  63. </div>
  64. <div class="searItem" v-for="item in 8">
  65. <el-checkbox></el-checkbox>
  66. </div>
  67. </div>
  68. </div>
  69. </el-col>
  70. </div>
  71. </el-col>
  72. </el-row>
  73. </div>
  74. </template>
  75. <script>
  76. import {
  77. listRole,
  78. getRole,
  79. delRole,
  80. addRole,
  81. updateRole,
  82. exportRole,
  83. dataScope,
  84. changeRoleStatus
  85. } from "@/api/system/role";
  86. import {
  87. treeselect as menuTreeselect,
  88. allLeafNodeById,
  89. treeMenuNotAddLeafNode
  90. } from "@/api/system/menu";
  91. import {
  92. treeselect as deptTreeselect,
  93. roleDeptTreeselect
  94. } from "@/api/system/dept";
  95. export default {
  96. name: "Role",
  97. data() {
  98. return {
  99. fullscreenLoading: false,
  100. searIndex: '',
  101. data: [],
  102. defaultProps: {
  103. children: 'children',
  104. label: 'label'
  105. },
  106. indexs: 3,
  107. // 遮罩层
  108. loading: true,
  109. // 选中数组
  110. ids: [],
  111. // 非单个禁用
  112. single: true,
  113. // 非多个禁用
  114. multiple: true,
  115. // 显示搜索条件
  116. showSearch: true,
  117. // 总条数
  118. total: 0,
  119. // 角色表格数据
  120. roleList: [],
  121. // 弹出层标题
  122. title: "",
  123. // 是否显示弹出层
  124. open: false,
  125. // 是否显示弹出层(数据权限)
  126. openDataScope: false,
  127. menuExpand: false,
  128. menuNodeAll: false,
  129. deptExpand: true,
  130. deptNodeAll: false,
  131. // 日期范围
  132. dateRange: [],
  133. // 状态数据字典
  134. statusOptions: [],
  135. // 数据范围选项
  136. dataScopeOptions: [{
  137. value: "1",
  138. label: "全部数据权限"
  139. },
  140. {
  141. value: "2",
  142. label: "自定数据权限"
  143. },
  144. {
  145. value: "3",
  146. label: "本部门数据权限"
  147. },
  148. {
  149. value: "4",
  150. label: "本部门及以下数据权限"
  151. },
  152. {
  153. value: "5",
  154. label: "仅本人数据权限"
  155. }
  156. ],
  157. // 菜单列表
  158. menuOptions: [],
  159. // 部门列表
  160. deptOptions: [],
  161. // 查询参数
  162. queryParams: {
  163. pageNum: 1,
  164. pageSize: 10,
  165. roleName: undefined,
  166. roleKey: undefined,
  167. status: undefined
  168. },
  169. roleId: '',
  170. // 表单参数
  171. form: {},
  172. // 表单校验
  173. rules: {
  174. roleName: [{
  175. required: true,
  176. message: "角色名称不能为空",
  177. trigger: "blur"
  178. }],
  179. roleKey: [{
  180. required: true,
  181. message: "权限字符不能为空",
  182. trigger: "blur"
  183. }],
  184. roleSort: [{
  185. required: true,
  186. message: "角色顺序不能为空",
  187. trigger: "blur"
  188. }]
  189. }
  190. };
  191. },
  192. created() {
  193. this.getList();
  194. this.getDicts("sys_normal_disable").then(response => {
  195. this.statusOptions = response.data;
  196. });
  197. },
  198. methods: {
  199. qxList(e) {
  200. allLeafNodeById(e.id).then(res => {
  201. console.log(res)
  202. })
  203. },
  204. refreshFn() {
  205. this.getList()
  206. this.deptOptions = []
  207. },
  208. searBtnFn(item) {
  209. this.roleId = item.id
  210. this.handleUpdate()
  211. },
  212. handleNodeClick() {
  213. console.log(221)
  214. },
  215. /** 查询角色列表 */
  216. getList() {
  217. this.loading = true;
  218. listRole(this.addDateRange(this.queryParams, this.dateRange)).then(
  219. response => {
  220. this.roleList = response.rows;
  221. this.total = response.total;
  222. this.loading = false;
  223. }
  224. );
  225. },
  226. /** 查询菜单树结构 */
  227. getMenuTreeselect() {
  228. menuTreeselect().then(response => {
  229. this.menuOptions = response.data;
  230. });
  231. },
  232. /** 查询部门树结构 */
  233. getDeptTreeselect() {
  234. deptTreeselect().then(response => {
  235. this.deptOptions = response.data;
  236. });
  237. },
  238. // 所有菜单节点数据
  239. getMenuAllCheckedKeys() {
  240. // 目前被选中的菜单节点
  241. let checkedKeys = this.$refs.menu.getCheckedKeys();
  242. // 半选中的菜单节点
  243. let halfCheckedKeys = this.$refs.menu.getHalfCheckedKeys();
  244. checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
  245. return checkedKeys;
  246. },
  247. // 所有部门节点数据
  248. getDeptAllCheckedKeys() {
  249. // 目前被选中的部门节点
  250. let checkedKeys = this.$refs.dept.getCheckedKeys();
  251. // 半选中的部门节点
  252. let halfCheckedKeys = this.$refs.dept.getHalfCheckedKeys();
  253. checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
  254. return checkedKeys;
  255. },
  256. /** 根据角色ID查询菜单树结构 */
  257. getRoleMenuTreeselect(id) {
  258. return treeMenuNotAddLeafNode(id).then(response => {
  259. this.menuOptions = response.menus;
  260. return response;
  261. });
  262. },
  263. /** 根据角色ID查询部门树结构 */
  264. getRoleDeptTreeselect(id) {
  265. return roleDeptTreeselect(id).then(response => {
  266. this.deptOptions = response.depts;
  267. return response;
  268. });
  269. },
  270. // 角色状态修改
  271. handleStatusChange(row) {
  272. let text = row.status === "0" ? "启用" : "停用";
  273. this.$confirm('确认要"' + text + '""' + row.roleName + '"角色吗?', "警告", {
  274. confirmButtonText: "确定",
  275. cancelButtonText: "取消",
  276. type: "warning"
  277. }).then(function() {
  278. return changeRoleStatus(row.id, row.status);
  279. }).then(() => {
  280. this.msgSuccess(text + "成功");
  281. }).catch(function() {
  282. row.status = row.status === "0" ? "1" : "0";
  283. });
  284. },
  285. // 取消按钮
  286. cancel() {
  287. this.open = false;
  288. this.reset();
  289. },
  290. // 取消按钮(数据权限)
  291. cancelDataScope() {
  292. this.openDataScope = false;
  293. this.reset();
  294. },
  295. // 表单重置
  296. reset() {
  297. if (this.$refs.menu != undefined) {
  298. this.$refs.menu.setCheckedKeys([]);
  299. }
  300. this.menuExpand = false,
  301. this.menuNodeAll = false,
  302. this.deptExpand = true,
  303. this.deptNodeAll = false,
  304. this.form = {
  305. id: undefined,
  306. roleName: undefined,
  307. roleKey: undefined,
  308. roleSort: 0,
  309. status: "0",
  310. menuIds: [],
  311. deptIds: [],
  312. menuCheckStrictly: true,
  313. deptCheckStrictly: true,
  314. remark: undefined
  315. };
  316. this.resetForm("form");
  317. },
  318. /** 搜索按钮操作 */
  319. handleQuery() {
  320. this.queryParams.pageNum = 1;
  321. this.getList();
  322. },
  323. /** 重置按钮操作 */
  324. resetQuery() {
  325. this.dateRange = [];
  326. this.resetForm("queryForm");
  327. this.handleQuery();
  328. },
  329. // 多选框选中数据
  330. handleSelectionChange(selection) {
  331. this.ids = selection.map(item => item.id)
  332. this.single = selection.length != 1
  333. this.multiple = !selection.length
  334. },
  335. // 树权限(展开/折叠)
  336. handleCheckedTreeExpand(value, type) {
  337. if (type == 'menu') {
  338. let treeList = this.menuOptions;
  339. for (let i = 0; i < treeList.length; i++) {
  340. this.$refs.menu.store.nodesMap[treeList[i].id].expanded = value;
  341. }
  342. } else if (type == 'dept') {
  343. let treeList = this.deptOptions;
  344. for (let i = 0; i < treeList.length; i++) {
  345. this.$refs.dept.store.nodesMap[treeList[i].id].expanded = value;
  346. }
  347. }
  348. },
  349. // 树权限(全选/全不选)
  350. handleCheckedTreeNodeAll(value, type) {
  351. if (type == 'menu') {
  352. this.$refs.menu.setCheckedNodes(value ? this.menuOptions : []);
  353. } else if (type == 'dept') {
  354. this.$refs.dept.setCheckedNodes(value ? this.deptOptions : []);
  355. }
  356. },
  357. // 树权限(父子联动)
  358. handleCheckedTreeConnect(value, type) {
  359. if (type == 'menu') {
  360. this.form.menuCheckStrictly = value ? true : false;
  361. } else if (type == 'dept') {
  362. this.form.deptCheckStrictly = value ? true : false;
  363. }
  364. },
  365. /** 新增按钮操作 */
  366. handleAdd() {
  367. this.reset();
  368. this.getMenuTreeselect();
  369. this.open = true;
  370. this.title = "添加角色";
  371. },
  372. /** 修改按钮操作 */
  373. handleUpdate() {
  374. this.reset();
  375. this.fullscreenLoading = true
  376. const roleMenu = this.getRoleMenuTreeselect(this.roleId);
  377. roleMenu.then(res => {
  378. // let checkedKeys = res.checkedKeys
  379. this.deptOptions = res.menus
  380. this.fullscreenLoading = false
  381. });
  382. },
  383. /** 选择角色权限范围触发 */
  384. dataScopeSelectChange(value) {
  385. if (value !== '2') {
  386. this.$refs.dept.setCheckedKeys([]);
  387. }
  388. },
  389. /** 分配数据权限操作 */
  390. handleDataScope(row) {
  391. this.reset();
  392. const roleDeptTreeselect = this.getRoleDeptTreeselect(row.id);
  393. getRole(row.id).then(response => {
  394. this.form = response.data;
  395. this.openDataScope = true;
  396. this.$nextTick(() => {
  397. roleDeptTreeselect.then(res => {
  398. this.$refs.dept.setCheckedKeys(res.checkedKeys);
  399. });
  400. });
  401. this.title = "分配数据权限";
  402. });
  403. },
  404. /** 提交按钮 */
  405. submitForm: function() {
  406. this.$refs["form"].validate(valid => {
  407. if (valid) {
  408. if (this.form.id != undefined) {
  409. this.form.menuIds = this.getMenuAllCheckedKeys();
  410. updateRole(this.form).then(response => {
  411. this.msgSuccess("修改成功");
  412. this.open = false;
  413. this.getList();
  414. });
  415. } else {
  416. this.form.menuIds = this.getMenuAllCheckedKeys();
  417. addRole(this.form).then(response => {
  418. this.msgSuccess("新增成功");
  419. this.open = false;
  420. this.getList();
  421. });
  422. }
  423. }
  424. });
  425. },
  426. /** 提交按钮(数据权限) */
  427. submitDataScope: function() {
  428. if (this.form.id != undefined) {
  429. this.form.deptIds = this.getDeptAllCheckedKeys();
  430. dataScope(this.form).then(response => {
  431. this.msgSuccess("修改成功");
  432. this.openDataScope = false;
  433. this.getList();
  434. });
  435. }
  436. },
  437. /** 删除按钮操作 */
  438. handleDelete(row) {
  439. const ids = row.id || this.ids;
  440. this.$confirm('是否确认删除角色编号为"' + ids + '"的数据项?', "警告", {
  441. confirmButtonText: "确定",
  442. cancelButtonText: "取消",
  443. type: "warning"
  444. }).then(function() {
  445. return delRole(ids);
  446. }).then(() => {
  447. this.getList();
  448. this.msgSuccess("删除成功");
  449. })
  450. },
  451. /** 导出按钮操作 */
  452. handleExport() {
  453. this.download('system/role/export', {
  454. ...this.queryParams
  455. }, `role_${new Date().getTime()}.xlsx`)
  456. }
  457. }
  458. };
  459. </script>
  460. <style lang="scss" scoped>
  461. .roleContrBox {
  462. background-color: #fff;
  463. border-radius: 6px;
  464. overflow: hidden;
  465. padding: 23px 0;
  466. height: calc(100% - 183px);
  467. }
  468. .roleContr {
  469. padding-left: 17px;
  470. .searContLeft {
  471. max-height: calc(100vh - 353px);
  472. overflow-y: auto;
  473. box-sizing: border-box;
  474. padding: 23px 17px 23px 23px;
  475. border-right: 2px solid #E5E5E5;
  476. &::-webkit-scrollbar {
  477. display: none;
  478. }
  479. }
  480. .searContRight {
  481. padding-left: 18px;
  482. .searTitle {
  483. display: flex;
  484. padding-left: 11px;
  485. margin-bottom: 26px;
  486. .searName {
  487. color: #343434;
  488. font-size: 12px;
  489. width: 156px;
  490. }
  491. .searItem {
  492. flex: 1;
  493. font-size: 12px;
  494. }
  495. }
  496. .searCont {
  497. display: flex;
  498. height: 23px;
  499. padding-left: 11px;
  500. align-items: center;
  501. margin-bottom: 4px;
  502. cursor: pointer;
  503. .searName {
  504. color: #343434;
  505. font-size: 12px;
  506. width: 156px;
  507. }
  508. .searItem {
  509. flex: 1;
  510. font-size: 12px;
  511. }
  512. &:hover {
  513. background-color: rgba(0, 0, 0, .1);
  514. }
  515. }
  516. .active {
  517. background-color: #CADBE4;
  518. .searName {
  519. color: #fff;
  520. }
  521. }
  522. }
  523. }
  524. .searBoxs {
  525. background-color: #fff;
  526. border-radius: 6px;
  527. box-sizing: border-box;
  528. padding: 23px;
  529. .searBox {
  530. display: flex;
  531. .searInput {
  532. flex: 1;
  533. height: 32px;
  534. margin-right: 8px;
  535. box-sizing: border-box;
  536. }
  537. input {
  538. width: 100%;
  539. height: 100%;
  540. background-color: #F7F6F6;
  541. border: none;
  542. padding: 0 7px;
  543. outline: none;
  544. &::placeholder {
  545. color: #AAAAAA;
  546. font-size: 12px;
  547. }
  548. }
  549. .searBtn {
  550. width: 30px;
  551. height: 32px;
  552. display: flex;
  553. justify-content: center;
  554. align-items: center;
  555. background-color: #3C8DBC;
  556. cursor: pointer;
  557. .icon {
  558. width: 18px;
  559. height: 17px;
  560. }
  561. }
  562. }
  563. .searList {
  564. padding: 10px 0;
  565. .searItem {
  566. padding: 0 8px;
  567. line-height: 30px;
  568. font-size: 12px;
  569. color: #343434;
  570. cursor: pointer;
  571. }
  572. .active {
  573. background-color: #CADBE4;
  574. color: #3C8DBC;
  575. }
  576. }
  577. }
  578. .app-container {
  579. background-color: #EFF0FF;
  580. height: calc(100vh - 84px);
  581. box-sizing: border-box;
  582. }
  583. .roleBox {
  584. padding: 0 23px;
  585. background: #fff;
  586. border-radius: 6px;
  587. .roleCol {
  588. padding: 20px 0;
  589. border-bottom: 1px solid #E5E5E5;
  590. .roleH {
  591. width: 18px;
  592. height: 8px;
  593. border-radius: 4px;
  594. background-color: #3C8DBC;
  595. margin-bottom: 8px;
  596. }
  597. span {
  598. font-size: 15px;
  599. color: #3C8DBC;
  600. }
  601. }
  602. .roleBot {
  603. padding: 22px 0;
  604. .roleBtn {
  605. height: 32px;
  606. display: flex;
  607. border-radius: 3px;
  608. justify-content: center;
  609. align-items: center;
  610. width: 83px;
  611. margin-right: 18px;
  612. .icon {
  613. width: 14px;
  614. height: 14px;
  615. margin-right: 7px;
  616. }
  617. span {
  618. color: #fff;
  619. font-size: 12px;
  620. }
  621. }
  622. }
  623. }
  624. </style>
  625. <style>
  626. .el-icon-my-export {
  627. background: url('~@/assets/images/icon_btn_bc@2x.png') center no-repeat;
  628. background-size: 13px 13px;
  629. /* background-size: cover;*/
  630. }
  631. .el-icon-my-export:before {
  632. content: "替";
  633. font-size: 16px;
  634. visibility: hidden;
  635. }
  636. .el-icon-my-export {
  637. font-size: 16px;
  638. }
  639. .el-icon-my-export:before {
  640. content: "\e611";
  641. }
  642. </style>