fz-index.vue 19 KB

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