index.vue 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. <template>
  2. <div class="system-role-container layout-padding">
  3. <div class="system-role-padding layout-padding-auto layout-padding-view">
  4. <div class="system-user-search mb15">
  5. <el-input v-model="state.formQuery.roleName" clearable size="default"
  6. placeholder="请输入角色名称" style="max-width: 180px"></el-input>
  7. <ext-button icon="ele-Search" type="success" plain class="ml10" @click="loadData" name="查询"/>
  8. <!-- <el-button size="default" type="primary" class="ml10">-->
  9. <!-- <el-icon>-->
  10. <!-- <ele-Search/>-->
  11. <!-- </el-icon>-->
  12. <!-- 查询-->
  13. <!-- </el-button>-->
  14. <el-button v-auth="'role.add'" size="default" type="success" class="ml10" @click="handleOpenDialog(0,false)">
  15. <el-icon>
  16. <ele-FolderAdd/>
  17. </el-icon>
  18. 新增角色
  19. </el-button>
  20. <el-button v-auth="'role.modify'" v-if="state.changed" size="default" type="success" class="ml10" @click="handleSaveRolePermission">
  21. <SvgIcon name="ele-Printer"/>
  22. 保存设置
  23. </el-button>
  24. </div>
  25. <el-table
  26. ref="tableRef"
  27. :data="state.tableData.data"
  28. v-loading="state.tableData.loading"
  29. border
  30. row-key="id"
  31. :tree-props="{children:'children'}"
  32. @cell-click="handleToggleRoleCheck"
  33. style="width: 100%">
  34. <template #empty>
  35. <el-empty></el-empty>
  36. </template>
  37. <el-table-column
  38. v-for="(col,idx) in state.columns"
  39. :key="col.prop"
  40. :label="col.label"
  41. :width="col.width"
  42. :min-width="col.minWidth"
  43. show-overflow-tooltip
  44. :fixed="col.fixed"
  45. :align="col.prop==='permName'?'left':'center'">
  46. <template #header>
  47. <template v-if="idx>0">
  48. <div class="role-header-item">{{ col.label }}
  49. <SvgIcon v-if="!state.immutableRoleList.includes(col.prop)" name="ele-Setting"
  50. @click="handleOpenDialog(col.prop.split('_')[1],false)"/>
  51. </div>
  52. </template>
  53. <template v-if="idx===0">
  54. 权限
  55. <span style="cursor: pointer;font-size: 12px;margin-left: 8px;color:#ccc" @click="handleExpandSwitch">{{state.expandAll?'收起':'展开'}} </span>
  56. </template>
  57. </template>
  58. <template #default="scope">
  59. <template v-if="scope.column.label!=='权限'">
  60. <el-icon color="#5FB878" v-if="scope.row[col.prop]">
  61. <CircleCheckFilled/>
  62. </el-icon>
  63. <span v-else>
  64. <SvgIcon name="ele-CircleCheck"></SvgIcon>
  65. </span>
  66. </template>
  67. <template v-else ><span :title="scope.row.perm">{{ scope.row[col.prop] }}</span></template>
  68. </template>
  69. </el-table-column>
  70. </el-table>
  71. </div>
  72. <RoleDialog ref="roleDialogRef" @refresh="loadData()"/>
  73. </div>
  74. </template>
  75. <script setup lang="ts" name="orgRole">
  76. import {defineAsyncComponent, reactive, onMounted, ref,nextTick} from 'vue';
  77. import {$body, $get} from "/@/utils/request";
  78. import u from "/@/utils/u";
  79. import {Msg} from "/@/utils/message";
  80. import {CircleCheckFilled} from '@element-plus/icons-vue'
  81. import ExtButton from "/@/components/form/ExtButton.vue";
  82. // 引入组件
  83. const RoleDialog = defineAsyncComponent(() => import('/@/views/admin/role/dialog.vue'));
  84. const tableRef = ref();
  85. // 定义变量内容
  86. const roleDialogRef = ref();
  87. const state = reactive({
  88. tableData: {
  89. data: [] as Array<any>,
  90. loading: false,
  91. },
  92. pageQuery: {
  93. pageNum: 1,
  94. pageSize: 20,
  95. },
  96. formQuery: {
  97. roleName: null,
  98. },
  99. columns: [{label: '权限', prop: 'permName', width: 200, fixed: 'left'}] as Array<IBaseField>,
  100. expandAll: false,
  101. immutableRoleList: [] as Array<string>,
  102. changed : false
  103. });
  104. const handleExpandSwitch = ()=>{
  105. state.expandAll = !state.expandAll;
  106. nextTick(()=>{
  107. state.tableData.data.forEach(row=>{
  108. tableRef.value.toggleRowExpansion(row,state.expandAll);
  109. })
  110. })
  111. }
  112. const loadPermissionList = (roleList: Array<any>) => {
  113. $get(`/permission/listPermission`, {pageSize: -1}).then((res: any) => {
  114. //构造权限数组
  115. let data = [] as Array<any>;
  116. var permMap = u.groupByKey(res, "pid");
  117. //console.log(permMap)
  118. let roleMap = new Map();
  119. state.immutableRoleList = [] as Array<string>;
  120. roleList.forEach(role => {
  121. state.columns.push({
  122. label: role.roleName,
  123. prop: 'role_' + role.id,
  124. width: (role.roleName).length * 60 + 45,
  125. });
  126. roleMap.set(role.id, role)
  127. });
  128. //console.log(state.columns)
  129. let topPermissionList = permMap['0']
  130. if (u.isEmptyOrNull(topPermissionList)) {
  131. Msg.message("没有权限数据", 'error')
  132. state.tableData.loading = false;
  133. return;
  134. }
  135. topPermissionList.forEach((top: any) => {
  136. let {id, name, value} = top;
  137. let childrenPermissionList = permMap[id.toString()];
  138. let record = {
  139. children: [] as Array<any>,
  140. permName: name,
  141. id: id,
  142. perm: value,
  143. // hasChildren: !u.isEmptyOrNull(childrenPermissionList)
  144. } as any;
  145. roleList.forEach(role => {
  146. let permArr = role.permissions ? role.permissions.split("|") : [];
  147. record['role_' + role.id] = permArr.includes(value);
  148. })
  149. let children = [] as Array<any>;
  150. if (!u.isEmptyOrNull(childrenPermissionList)) {
  151. childrenPermissionList.forEach((child: any) => {
  152. let childRecord = {
  153. permName: child.name,
  154. id: child.id,
  155. perm: child.value,
  156. } as any;
  157. roleList.forEach(role => {
  158. let permArr = role.permissions ? role.permissions.split("|") : [];
  159. childRecord['role_' + role.id] = permArr.includes(child.value);
  160. })
  161. children.push(childRecord);
  162. });
  163. //
  164. record.children = children;
  165. }
  166. data.push(record);
  167. })
  168. state.tableData.data = data;
  169. //console.log(state.tableData.data)
  170. state.tableData.loading = false;
  171. }).catch(e => {
  172. ////console.log(e)
  173. state.tableData.loading = false;
  174. })
  175. }
  176. // 初始化表格数据
  177. const loadData = () => {
  178. state.columns = [{label: '权限', prop: 'permName', width: 120, fixed: 'left'}];
  179. state.tableData.data = [];
  180. state.tableData.loading = true;
  181. $get(`/role/list`, {...state.formQuery}).then((res: any) => {
  182. //构造权限数组
  183. loadPermissionList(res);
  184. }).catch(e => {
  185. //console.error(e)
  186. state.tableData.loading = false;
  187. })
  188. };
  189. // 打开新增角色弹窗
  190. const handleOpenDialog = (id: number, readonly: boolean) => {
  191. roleDialogRef.value.openDialog(id, readonly);
  192. };
  193. const handleToggleRoleCheck = (row, column, cell, event) => {
  194. state.changed = true;
  195. //console.log(row, column, cell)
  196. if(column.rawColumnKey==='permName'){
  197. // tableRef.value
  198. return;
  199. }
  200. let index = state.tableData.data.findIndex(k => k.id === row.id);
  201. if (index >= 0) {
  202. let record = state.tableData.data[index];
  203. ////console.log(record)
  204. let bol = !record[column.rawColumnKey];
  205. state.tableData.data[index][column.rawColumnKey] = bol;
  206. if (!u.isEmptyOrNull(record.children)) {
  207. record.children.forEach((r:any)=>{
  208. r[column.rawColumnKey]= bol;
  209. })
  210. }
  211. } else {
  212. state.tableData.data.forEach(record => {
  213. if (!u.isEmptyOrNull(record.children)) {
  214. let r = record.children.find((k: any) => k.id === row.id);
  215. if (r) {
  216. r[column.rawColumnKey] = !r[column.rawColumnKey]
  217. return;
  218. }
  219. }
  220. })
  221. }
  222. }
  223. const handleSaveRolePermission = () => {
  224. let updateRoles = [] as Array<any>;
  225. let map = new Map();
  226. // 从 columns 定义获取角色列名,避免 Object.keys 采集到 Vue/ElementPlus 注入的脏属性
  227. let roleColumns = state.columns
  228. .filter(col => col.prop && col.prop.startsWith("role_"))
  229. .map(col => col.prop);
  230. state.tableData.data.forEach(record => {
  231. roleColumns.forEach((k: string) => {
  232. if (record[k]) {
  233. let roleId = k.split("_")[1];
  234. let perms = map.get(roleId);
  235. if (!perms) {
  236. map.set(roleId, [record.perm]);
  237. } else {
  238. perms.push(record.perm);
  239. }
  240. }
  241. if (!u.isEmptyOrNull(record.children)) {
  242. record.children.forEach((child: any) => {
  243. if (child[k]) {
  244. let roleId = k.split("_")[1];
  245. let perms = map.get(roleId);
  246. if (!perms) {
  247. map.set(roleId, [child.perm]);
  248. } else {
  249. perms.push(child.perm);
  250. }
  251. }
  252. });
  253. }
  254. });
  255. });
  256. ////console.log(map)
  257. map.forEach((value: Array<string>, key: any) => {
  258. updateRoles.push({
  259. id: key,
  260. permissions: value.join("|")
  261. });
  262. })
  263. $body(`/role/saveList`,updateRoles).then(()=>{
  264. Msg.message("更新成功","success");
  265. state.changed = false;
  266. nextTick(()=>{
  267. loadData();
  268. })
  269. }).catch(() => {
  270. Msg.message("保存失败,请稍后重试", "error");
  271. })
  272. }
  273. // 页面加载时
  274. onMounted(() => {
  275. loadData();
  276. });
  277. </script>
  278. <style scoped lang="scss">
  279. .role-header-item {
  280. display: inline-flex;
  281. justify-content: space-around;
  282. align-items: center;
  283. i {
  284. margin-left: 3px;
  285. cursor: pointer;
  286. }
  287. }
  288. .permission-box {
  289. }
  290. .system-role-container {
  291. .system-role-padding {
  292. padding: 15px;
  293. .el-table {
  294. flex: 1;
  295. }
  296. }
  297. }
  298. :deep(.el-table thead th.el-table__cell ) {
  299. background: var(--el-fill-color-light);
  300. }
  301. </style>