From e35e6309bee3a50b98eb93049663d6984cb08379 Mon Sep 17 00:00:00 2001
From: sin <2943460818@qq.com>
Date: Tue, 12 Mar 2019 22:52:50 +0800
Subject: [PATCH 1/3] =?UTF-8?q?-=20=E5=A2=9E=E5=8A=A0=E7=AE=A1=E7=90=86?=
=?UTF-8?q?=E5=91=98=20=E8=A7=92=E8=89=B2=E5=88=86=E9=85=8D=EF=BC=8C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
admin-web/src/models/admin/adminList.js | 54 ++++++++
admin-web/src/models/admin/roleList.js | 66 +--------
admin-web/src/pages/Admin/AdminList.js | 175 +++++++++++++++++++++++-
admin-web/src/services/admin.js | 12 ++
admin-web/src/utils/tree.utils.js | 67 +++++++++
5 files changed, 304 insertions(+), 70 deletions(-)
create mode 100644 admin-web/src/utils/tree.utils.js
diff --git a/admin-web/src/models/admin/adminList.js b/admin-web/src/models/admin/adminList.js
index a21faa0d3..6adf934fe 100644
--- a/admin-web/src/models/admin/adminList.js
+++ b/admin-web/src/models/admin/adminList.js
@@ -1,11 +1,15 @@
import { message } from 'antd';
+import { buildTreeNode, findCheckedKeys } from '../../utils/tree.utils';
import {
addAdmin,
updateAdmin,
updateAdminStatus,
deleteAdmin,
queryAdmin,
+ queryAdminRoleList,
+ adminRoleAssign,
} from '../../services/admin';
+import { arrayToStringParams } from '../../utils/request.qs';
export default {
namespace: 'adminList',
@@ -15,6 +19,10 @@ export default {
count: 0,
pageNo: 0,
pageSize: 10,
+
+ roleList: [],
+ roleCheckedKeys: [],
+ roleAssignLoading: false,
},
effects: {
@@ -78,6 +86,40 @@ export default {
},
});
},
+ *queryRoleList({ payload }, { call, put }) {
+ yield put({
+ type: 'changeRoleAssignLoading',
+ payload: true,
+ });
+
+ const response = yield call(queryAdminRoleList, payload);
+ const roleList = response.data;
+ const roleTreeData = buildTreeNode(roleList, 'name', 'id');
+ const roleCheckedKeys = findCheckedKeys(roleList);
+
+ yield put({
+ type: 'querySuccess',
+ payload: {
+ roleList: roleTreeData,
+ roleCheckedKeys,
+ },
+ });
+
+ yield put({
+ type: 'changeRoleAssignLoading',
+ payload: false,
+ });
+ },
+ *roleAssign({ payload }, { call }) {
+ const params = {
+ id: payload.id,
+ roleIds: arrayToStringParams(payload.roleIds),
+ };
+ const response = yield call(adminRoleAssign, params);
+ if (response.code === 0) {
+ message.info('操作成功!');
+ }
+ },
},
reducers: {
@@ -87,5 +129,17 @@ export default {
...payload,
};
},
+ changeRoleCheckedKeys(state, { payload }) {
+ return {
+ ...state,
+ roleCheckedKeys: payload,
+ };
+ },
+ changeRoleAssignLoading(state, { payload }) {
+ return {
+ ...state,
+ roleAssignLoading: payload,
+ };
+ },
},
};
diff --git a/admin-web/src/models/admin/roleList.js b/admin-web/src/models/admin/roleList.js
index 32071b535..fcec9a9b7 100644
--- a/admin-web/src/models/admin/roleList.js
+++ b/admin-web/src/models/admin/roleList.js
@@ -1,5 +1,6 @@
import { message } from 'antd';
import { arrayToStringParams } from '../../utils/request.qs';
+import { buildTreeNode, findAllNodes, findCheckedKeys } from '../../utils/tree.utils';
import {
addRole,
updateRole,
@@ -9,71 +10,6 @@ import {
roleAssignResource,
} from '../../services/admin';
-function buildTreeNode(nodes, titleKey, nodeKey) {
- return nodes.map(item => {
- const res = {};
- if (item.children) {
- res.children = buildTreeNode(item.children, titleKey, nodeKey);
- }
- res.title = `${item.id}-${item[titleKey]}`;
- res.key = item[nodeKey];
- return res;
- });
-}
-
-function findNodes(id, nodes) {
- const res = [];
- for (let i = 0; i < nodes.length; i += 1) {
- const node = nodes[i];
- if (node.key === id) {
- res.push(node.key);
- break;
- } else {
- const childNodes = findNodes(id, node.children);
- if (childNodes.length) {
- res.push(node.key);
- for (let j = 0; j < childNodes.length; j += 1) {
- res.push(childNodes[j]);
- }
- break;
- }
- }
- }
- return res;
-}
-
-function findAllNodes(resourceIds, nodes) {
- const findNodesArray = [];
- for (let i = 0; i < resourceIds.length; i += 1) {
- const findNodesData = findNodes(resourceIds[i], nodes);
- if (findNodesData) {
- for (let j = 0; j < findNodesData.length; j += 1) {
- const jD = findNodesData[j];
- if (findNodesArray.indexOf(jD) === -1) {
- findNodesArray.push(jD);
- }
- }
- }
- }
- return findNodesArray;
-}
-
-function findCheckedKeys(nodes) {
- let res = [];
- for (let i = 0; i < nodes.length; i += 1) {
- const node = nodes[i];
- if (node.children) {
- const findChildrenNodes = findCheckedKeys(node.children);
- if (findChildrenNodes) {
- res = res.concat(findChildrenNodes);
- }
- } else if (node.assigned === true) {
- res.push(node.id);
- }
- }
- return res;
-}
-
export default {
namespace: 'roleList',
diff --git a/admin-web/src/pages/Admin/AdminList.js b/admin-web/src/pages/Admin/AdminList.js
index ab25d77c7..d2da4e2ab 100644
--- a/admin-web/src/pages/Admin/AdminList.js
+++ b/admin-web/src/pages/Admin/AdminList.js
@@ -2,14 +2,13 @@
import React, { PureComponent, Fragment } from 'react';
import { connect } from 'dva';
-import moment from 'moment';
-import { Card, Form, Input, Select, Button, Modal, message, Table, Divider } from 'antd';
+import { Card, Form, Input, Button, Modal, message, Table, Divider, Tree, Spin } from 'antd';
import PageHeaderWrapper from '@/components/PageHeaderWrapper';
import styles from './AdminList.less';
const FormItem = Form.Item;
-const { Option } = Select;
+const { TreeNode } = Tree;
const status = ['未知', '正常', '禁用'];
// 添加 form 表单
@@ -64,6 +63,78 @@ const CreateForm = Form.create()(props => {
);
});
+// 角色分配
+const RoleAssignModal = Form.create()(props => {
+ const {
+ modalVisible,
+ form,
+ handleOk,
+ handleModalVisible,
+ treeData,
+ checkedKeys,
+ loading,
+ handleCheckBoxClick,
+ } = props;
+
+ const renderTreeNodes = data => {
+ return data.map(item => {
+ if (item.children) {
+ return (
+
+ {renderTreeNodes(item.children)}
+
+ );
+ }
+ return ;
+ });
+ };
+
+ const renderModalContent = treeData => {
+ const RenderTreeNodes = renderTreeNodes(treeData);
+ if (RenderTreeNodes) {
+ return (
+
+ {form.getFieldDecorator('name', {})(
+
+ {renderTreeNodes(treeData)}
+
+ )}
+
+ );
+ } else {
+ return null;
+ }
+ };
+
+ const okHandle = () => {
+ form.validateFields((err, fieldsValue) => {
+ if (err) return;
+ form.resetFields();
+ handleOk({
+ fields: fieldsValue,
+ });
+ });
+ };
+
+ return (
+ handleModalVisible()}
+ >
+ {renderModalContent(treeData)}
+
+ );
+});
+
@connect(({ adminList, loading }) => ({
list: adminList.list,
data: adminList,
@@ -75,6 +146,9 @@ class ResourceList extends PureComponent {
modalVisible: false,
modalType: 'add', //add update
initValues: {},
+
+ modalRoleVisible: false,
+ modalRoleRow: {},
};
componentDidMount() {
@@ -160,9 +234,87 @@ class ResourceList extends PureComponent {
});
}
+ handleDelete(row) {
+ const { dispatch, data } = this.props;
+ const queryParams = {
+ pageNo: data.pageNo,
+ pageSize: data.pageSize,
+ };
+
+ Modal.confirm({
+ title: `确认删除?`,
+ content: `${row.username}`,
+ onOk() {
+ dispatch({
+ type: 'adminList/delete',
+ payload: {
+ body: {
+ id: row.id,
+ },
+ queryParams,
+ },
+ });
+ },
+ onCancel() {},
+ });
+ }
+
+ handleRoleAssign = row => {
+ const { dispatch } = this.props;
+ this.setState({
+ modalRoleVisible: !!true,
+ modalRoleRow: row,
+ });
+
+ dispatch({
+ type: 'adminList/queryRoleList',
+ payload: {
+ id: row.id,
+ },
+ });
+ };
+
+ handleRoleAssignCheckBoxClick = checkedKeys => {
+ const { dispatch } = this.props;
+ const newCheckedKeys = checkedKeys.map(item => {
+ return parseInt(item);
+ });
+ dispatch({
+ type: 'adminList/changeRoleCheckedKeys',
+ payload: newCheckedKeys,
+ });
+ };
+
+ handleRoleAssignOK = () => {
+ const { dispatch, data } = this.props;
+ const { modalRoleRow } = this.state;
+ dispatch({
+ type: 'adminList/roleAssign',
+ payload: {
+ id: modalRoleRow.id,
+ roleIds: data.roleCheckedKeys,
+ },
+ });
+ this.handleRoleAssignModalVisibleClose(false);
+ };
+
+ handleRoleAssignModalVisibleClose = fag => {
+ this.setState({
+ modalRoleVisible: !!fag,
+ });
+ };
+
render() {
- const { list } = this.props;
- const { modalVisible, modalType, initValues, defaultExpandAllRows } = this.state;
+ const { list, data } = this.props;
+ const { roleList, roleCheckedKeys, roleAssignLoading } = data;
+ const {
+ modalVisible,
+ modalType,
+ initValues,
+ defaultExpandAllRows,
+ modalRoleVisible,
+ } = this.state;
+
const parentMethods = {
handleAdd: this.handleAdd,
handleModalVisible: this.handleModalVisible,
@@ -194,12 +346,15 @@ class ResourceList extends PureComponent {
},
{
title: '操作',
+ width: 300,
render: (text, record) => {
const statusText = record.status === 1 ? '确认禁用' : '取消禁用';
return (
this.handleModalVisible(true, 'update', record)}>更新
+ this.handleRoleAssign(record)}>角色分配
+
this.handleStatus(record)}>
{statusText}
@@ -235,6 +390,16 @@ class ResourceList extends PureComponent {
/>
+
+ this.handleRoleAssignModalVisibleClose(false)}
+ />
);
}
diff --git a/admin-web/src/services/admin.js b/admin-web/src/services/admin.js
index deb177f4c..35efff580 100644
--- a/admin-web/src/services/admin.js
+++ b/admin-web/src/services/admin.js
@@ -43,6 +43,18 @@ export async function deleteAdmin(params) {
});
}
+export async function queryAdminRoleList(params) {
+ return request(`/admin-api/admins/admin/role_list?${stringify(params)}`, {
+ method: 'GET',
+ });
+}
+
+export async function adminRoleAssign(params) {
+ return request(`/admin-api/admins/admin/assign_role?${stringify(params)}`, {
+ method: 'POST',
+ });
+}
+
// resource
export async function addResource(params) {
diff --git a/admin-web/src/utils/tree.utils.js b/admin-web/src/utils/tree.utils.js
new file mode 100644
index 000000000..bb0653ff5
--- /dev/null
+++ b/admin-web/src/utils/tree.utils.js
@@ -0,0 +1,67 @@
+// tree 工具
+
+export function buildTreeNode(nodes, titleKey, nodeKey) {
+ return nodes.map(item => {
+ const res = {};
+ if (item.children) {
+ res.children = buildTreeNode(item.children, titleKey, nodeKey);
+ }
+ res.title = `${item.id}-${item[titleKey]}`;
+ res.key = item[nodeKey];
+ return res;
+ });
+}
+
+// @primary
+function findNodes(id, nodes) {
+ const res = [];
+ for (let i = 0; i < nodes.length; i += 1) {
+ const node = nodes[i];
+ if (node.key === id) {
+ res.push(node.key);
+ break;
+ } else {
+ const childNodes = findNodes(id, node.children);
+ if (childNodes.length) {
+ res.push(node.key);
+ for (let j = 0; j < childNodes.length; j += 1) {
+ res.push(childNodes[j]);
+ }
+ break;
+ }
+ }
+ }
+ return res;
+}
+
+export function findAllNodes(resourceIds, nodes) {
+ const findNodesArray = [];
+ for (let i = 0; i < resourceIds.length; i += 1) {
+ const findNodesData = findNodes(resourceIds[i], nodes);
+ if (findNodesData) {
+ for (let j = 0; j < findNodesData.length; j += 1) {
+ const jD = findNodesData[j];
+ if (findNodesArray.indexOf(jD) === -1) {
+ findNodesArray.push(jD);
+ }
+ }
+ }
+ }
+ return findNodesArray;
+}
+
+export function findCheckedKeys(nodes) {
+ let res = [];
+ for (let i = 0; i < nodes.length; i += 1) {
+ const node = nodes[i];
+ if (node.children) {
+ const findChildrenNodes = findCheckedKeys(node.children);
+ if (findChildrenNodes) {
+ res = res.concat(findChildrenNodes);
+ }
+ } else if (node.assigned === true) {
+ res.push(node.id);
+ }
+ }
+ return res;
+}
From 2385f239abf5b67c36d1ad0b905e4dcdf25b609b Mon Sep 17 00:00:00 2001
From: sin <2943460818@qq.com>
Date: Tue, 12 Mar 2019 22:53:18 +0800
Subject: [PATCH 2/3] =?UTF-8?q?-=20=E4=BC=98=E5=8C=96=20role=20tree?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
admin-web/src/pages/Admin/RoleList.js | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/admin-web/src/pages/Admin/RoleList.js b/admin-web/src/pages/Admin/RoleList.js
index 99abfcf3d..2a35c29e9 100644
--- a/admin-web/src/pages/Admin/RoleList.js
+++ b/admin-web/src/pages/Admin/RoleList.js
@@ -21,7 +21,6 @@ import PageHeaderWrapper from '@/components/PageHeaderWrapper';
import styles from './RoleList.less';
const FormItem = Form.Item;
-const { Option } = Select;
const { TreeNode } = Tree;
// 添加 form 表单
@@ -65,7 +64,7 @@ const CreateForm = Form.create()(props => {
);
});
-// 添加 form 表单
+// 角色分配
const AssignModal = Form.create()(props => {
const {
modalVisible,
From 8d6cfce8732def24ee53fab6e97c9f206adfcd95 Mon Sep 17 00:00:00 2001
From: sin <2943460818@qq.com>
Date: Tue, 12 Mar 2019 22:53:39 +0800
Subject: [PATCH 3/3] =?UTF-8?q?-=20=E4=BF=AE=E6=94=B9=E5=90=8E=E5=8F=B0?=
=?UTF-8?q?=E9=85=8D=E7=BD=AE=E8=8F=9C=E5=8D=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
admin-web/src/models/{menu.jsx => menu.js} | 109 ++++++++++++++++-----
1 file changed, 85 insertions(+), 24 deletions(-)
rename admin-web/src/models/{menu.jsx => menu.js} (59%)
diff --git a/admin-web/src/models/menu.jsx b/admin-web/src/models/menu.js
similarity index 59%
rename from admin-web/src/models/menu.jsx
rename to admin-web/src/models/menu.js
index becae1d44..759930e74 100644
--- a/admin-web/src/models/menu.jsx
+++ b/admin-web/src/models/menu.js
@@ -72,20 +72,87 @@ const filterMenuData = menuData => {
.filter(item => item);
};
-/**
- * 递归构建服务端,配置的菜单
- * @param resultMenuData
- */
-const recursionBuildResultMenu = resultMenuData => {
- const res = {};
- for (let i = 0; i < resultMenuData.length; i += 1) {
- const menuItem = resultMenuData[i];
- // 存在子节点
- res[menuItem.handler] = {
- ...menuItem,
+// 用于生成uuid
+function S4() {
+ return ((1 + Math.random()) * 0x10000 || 0).toString(16).substring(1);
+}
+function guid() {
+ return S4() + S4() + S4() + S4() + S4() + S4() + S4() + S4();
+}
+
+const findRootMenu = (antDataMenus, rootAntDataMenu, requestDataMenu) => {
+ let res;
+ for (let i = 0; i < antDataMenus.length; i += 1) {
+ const antDataMenu = antDataMenus[i];
+ if (antDataMenu.path === requestDataMenu.handler) {
+ res = rootAntDataMenu;
+ break;
+ }
+ if (antDataMenu.children) {
+ res = findRootMenu(antDataMenu.children, antDataMenu, requestDataMenu);
+ break;
+ }
+ }
+ return res;
+};
+
+const buildTreeMenu = (antMenuData, moveChildrenMenusData, requestDataMenus) => {
+ return requestDataMenus.map(item => {
+ if (!item.handler) {
+ // root 节点
+ const uuid = `sms${guid()}`;
+ const res = {
+ icon: 'user',
+ name: item.displayName,
+ path: uuid,
+ };
+
+ // 子节点
+ if (item.children) {
+ // 通过子节点找到对于的父节点,设置 path,没有则是 uuid
+ const rootMenu = findRootMenu(antMenuData, {}, item.children[0]);
+ if (rootMenu) {
+ res.path = rootMenu.path;
+ }
+
+ // 开始递归构建数据结构
+ const childrenMenus = buildTreeMenu(antMenuData, moveChildrenMenusData, item.children);
+ res.children = childrenMenus;
+ }
+ return res;
+ }
+
+ // moveChildrenMenusData 是一个 map,对比 url 地址是否存在,不存在就给一个 404 的页面
+ const handleMapperData = moveChildrenMenusData[item.handler];
+ if (handleMapperData) {
+ return {
+ ...handleMapperData,
+ icon: 'user',
+ name: item.displayName,
+ path: item.handler,
+ };
+ }
+
+ // 没有就返回404页面
+ return moveChildrenMenusData['/exception/404'];
+ });
+};
+
+const moveChildrenMenus = antDataMenus => {
+ let res = {};
+ for (let i = 0; i < antDataMenus.length; i += 1) {
+ const antDataMenu = antDataMenus[i];
+ res[antDataMenu.path] = {
+ ...res,
+ ...antDataMenu,
};
- if (menuItem.children) {
- res[menuItem.handler].children = recursionBuildResultMenu(menuItem.children);
+
+ if (antDataMenu.children) {
+ const childrenMenus = moveChildrenMenus(antDataMenu.children);
+ res = {
+ ...res,
+ ...childrenMenus,
+ };
}
}
return res;
@@ -126,21 +193,15 @@ export default {
*getMenuData({ payload }, { put, call }) {
const { data } = yield call(getAdminMenus);
const { routes, authority } = payload;
+
// authority 已经不适用
const antMenuData = filterMenuData(memoizeOneFormatter(routes, authority));
-
let menuData = antMenuData;
- const resultMenuData = data;
+ // const resultMenuData = data;
if (data !== 'all') {
- // 处理后台数据结构
- const buildResultMenu = recursionBuildResultMenu(resultMenuData);
- // 过滤没有权限的菜单
- menuData = antMenuData.filter(item => {
- if (buildResultMenu[item.path]) {
- return item;
- }
- return false;
- });
+ const moveChildrenMenusData = moveChildrenMenus(antMenuData);
+ const buildTreeMenuData = buildTreeMenu(antMenuData, moveChildrenMenusData, data);
+ menuData = buildTreeMenuData;
}
// 生成 menu 和 router mapping