mirror of
https://github.com/chillzhuang/Sword
synced 2024-12-22 08:59:24 +08:00
🎉 3.2.0.RELEASE 新增灵活数据权限特性
This commit is contained in:
parent
a7ea876307
commit
adcaaf5016
@ -102,6 +102,29 @@ export default [
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/authority',
|
||||
routes: [
|
||||
{
|
||||
path: '/authority/role',
|
||||
routes: [
|
||||
{ path: '/authority/role', redirect: '/authority/role/list' },
|
||||
{ path: '/authority/role/list', component: './Authority/Role/Role' },
|
||||
{ path: '/authority/role/add', component: './Authority/Role/RoleAdd' },
|
||||
{ path: '/authority/role/add/:id', component: './Authority/Role/RoleAdd' },
|
||||
{ path: '/authority/role/edit/:id', component: './Authority/Role/RoleEdit' },
|
||||
{ path: '/authority/role/view/:id', component: './Authority/Role/RoleView' },
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/authority/datascope',
|
||||
routes: [
|
||||
{ path: '/authority/datascope', redirect: '/authority/datascope/list' },
|
||||
{ path: '/authority/datascope/list', component: './Authority/DataScope/DataScope' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/system',
|
||||
routes: [
|
||||
@ -148,17 +171,6 @@ export default [
|
||||
{ path: '/system/post/view/:id', component: './System/Post/PostView' },
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/system/role',
|
||||
routes: [
|
||||
{ path: '/system/role', redirect: '/system/role/list' },
|
||||
{ path: '/system/role/list', component: './System/Role/Role' },
|
||||
{ path: '/system/role/add', component: './System/Role/RoleAdd' },
|
||||
{ path: '/system/role/add/:id', component: './System/Role/RoleAdd' },
|
||||
{ path: '/system/role/edit/:id', component: './System/Role/RoleEdit' },
|
||||
{ path: '/system/role/view/:id', component: './System/Role/RoleView' },
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/system/menu',
|
||||
routes: [
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "sword",
|
||||
"version": "3.1.0",
|
||||
"version": "3.2.0",
|
||||
"description": "An out-of-box UI solution for enterprise applications",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
@ -2,6 +2,16 @@ import { getAuthority } from '../utils/authority';
|
||||
|
||||
export const MENU_NAMESPACE = 'menu';
|
||||
|
||||
export function MENU_REFRESH_ROUTE(topMenuId, callback) {
|
||||
return {
|
||||
type: `${MENU_NAMESPACE}/refreshMenuData`,
|
||||
payload: {
|
||||
topMenuId,
|
||||
},
|
||||
callback,
|
||||
};
|
||||
}
|
||||
|
||||
export function MENU_REFRESH_DATA() {
|
||||
return {
|
||||
type: `${MENU_NAMESPACE}/fetchMenuData`,
|
||||
@ -16,6 +26,13 @@ export function MENU_LIST(payload) {
|
||||
};
|
||||
}
|
||||
|
||||
export function MENU_PARENT_LIST(payload) {
|
||||
return {
|
||||
type: `${MENU_NAMESPACE}/fetchParentList`,
|
||||
payload,
|
||||
};
|
||||
}
|
||||
|
||||
export function MENU_INIT() {
|
||||
return {
|
||||
type: `${MENU_NAMESPACE}/fetchInit`,
|
||||
@ -59,3 +76,24 @@ export function MENU_SELECT_ICON(icon) {
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function MENU_SHOW_DRAWER(payload) {
|
||||
return {
|
||||
type: `${MENU_NAMESPACE}/showDrawer`,
|
||||
payload,
|
||||
};
|
||||
}
|
||||
|
||||
export function MENU_LOAD_DATA_SCOPE_DRAWER(payload) {
|
||||
return {
|
||||
type: `${MENU_NAMESPACE}/loadDataScopeDrawer`,
|
||||
payload,
|
||||
};
|
||||
}
|
||||
|
||||
export function MENU_LOAD_DATA_SCOPE_DICT() {
|
||||
return {
|
||||
type: `${MENU_NAMESPACE}/loadDataScopeDict`,
|
||||
payload: { code: 'data_scope_type' },
|
||||
};
|
||||
}
|
||||
|
@ -14,6 +14,13 @@ export function ROLE_INIT() {
|
||||
};
|
||||
}
|
||||
|
||||
export function ROLE_INIT_BY_ID(roleId) {
|
||||
return {
|
||||
type: `${ROLE_NAMESPACE}/fetchInitById`,
|
||||
payload: { roleId },
|
||||
};
|
||||
}
|
||||
|
||||
export function ROLE_DETAIL(id) {
|
||||
return {
|
||||
type: `${ROLE_NAMESPACE}/fetchDetail`,
|
||||
|
@ -8,7 +8,7 @@ const FooterView = () => (
|
||||
<GlobalFooter
|
||||
copyright={
|
||||
<Fragment>
|
||||
Copyright <Icon type="copyright" /> 2020 SpringBlade{' '}
|
||||
Copyright <Icon type="copyright" /> 2021 SpringBlade{' '}
|
||||
<a
|
||||
key="github"
|
||||
title="git"
|
||||
|
@ -27,7 +27,7 @@ const links = [
|
||||
|
||||
const copyright = (
|
||||
<Fragment>
|
||||
Copyright <Icon type="copyright" /> 2020 SpringBlade{' '}
|
||||
Copyright <Icon type="copyright" /> 2021 SpringBlade{' '}
|
||||
<a
|
||||
key="github"
|
||||
title="git"
|
||||
|
@ -13,4 +13,5 @@ export default {
|
||||
'button.role.name': 'grant role',
|
||||
'button.reset-password.name': 'reset password',
|
||||
'button.back.name': 'back',
|
||||
'button.setting.name': 'setting',
|
||||
};
|
||||
|
@ -8,6 +8,9 @@ export default {
|
||||
'menu.desk.notice': 'notice',
|
||||
'menu.base': 'base',
|
||||
'menu.base.region': 'region',
|
||||
'menu.authority': 'authority',
|
||||
'menu.authority.role': 'role',
|
||||
'menu.authority.data_scope': 'data scope',
|
||||
'menu.system': 'system',
|
||||
'menu.system.user': 'user',
|
||||
'menu.system.dept': 'department',
|
||||
|
@ -13,4 +13,5 @@ export default {
|
||||
'button.role.name': '角色配置',
|
||||
'button.reset-password.name': '密码重置',
|
||||
'button.back.name': '返回',
|
||||
'button.setting.name': '配置',
|
||||
};
|
||||
|
@ -8,6 +8,9 @@ export default {
|
||||
'menu.desk.notice': '通知公告',
|
||||
'menu.base': '基础配置',
|
||||
'menu.base.region': '行政区划',
|
||||
'menu.authority': '权限管理',
|
||||
'menu.authority.role': '角色管理',
|
||||
'menu.authority.data_scope': '数据权限',
|
||||
'menu.system': '系统管理',
|
||||
'menu.system.user': '用户管理',
|
||||
'menu.system.dept': '部门管理',
|
||||
|
@ -13,4 +13,5 @@ export default {
|
||||
'button.role.name': '角色配置',
|
||||
'button.reset-password.name': '密碼重置',
|
||||
'button.back.name': '返回',
|
||||
'button.setting.name': '配置',
|
||||
};
|
||||
|
@ -8,6 +8,9 @@ export default {
|
||||
'menu.desk.notice': '通知公告',
|
||||
'menu.base': '基礎配置',
|
||||
'menu.base.region': '行政區劃',
|
||||
'menu.authority': '權限管理',
|
||||
'menu.authority.role': '角色管理',
|
||||
'menu.authority.data_scope': '數據權限',
|
||||
'menu.system': '系統管理',
|
||||
'menu.system.user': '用戶管理',
|
||||
'menu.system.dept': '部門管理',
|
||||
|
@ -9,11 +9,14 @@ import {
|
||||
dynamicRoutes,
|
||||
dynamicButtons,
|
||||
list,
|
||||
parentList,
|
||||
submit,
|
||||
detail,
|
||||
remove,
|
||||
tree,
|
||||
dataScopeList,
|
||||
} from '../services/menu';
|
||||
import { dict } from '../services/dict';
|
||||
import { getRoutes, setRoutes, getButtons, setButtons } from '../utils/authority';
|
||||
import { MENU_NAMESPACE } from '../actions/menu';
|
||||
import { formatRoutes, formatButtons } from '../utils/utils';
|
||||
@ -119,7 +122,19 @@ export default {
|
||||
init: {
|
||||
tree: [],
|
||||
},
|
||||
dict: {
|
||||
dataScopeType: [],
|
||||
},
|
||||
detail: {},
|
||||
drawer: {
|
||||
visible: false,
|
||||
menuId: '',
|
||||
menuName: '',
|
||||
dataScope: {
|
||||
list: [],
|
||||
pagination: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
effects: {
|
||||
@ -158,6 +173,18 @@ export default {
|
||||
});
|
||||
}
|
||||
},
|
||||
*fetchParentList({ payload }, { call, put }) {
|
||||
const response = yield call(parentList, payload);
|
||||
if (response.success) {
|
||||
yield put({
|
||||
type: 'saveList',
|
||||
payload: {
|
||||
list: response.data,
|
||||
pagination: false,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
*fetchInit({ payload }, { call, put }) {
|
||||
const response = yield call(tree, payload);
|
||||
if (response.success) {
|
||||
@ -194,6 +221,41 @@ export default {
|
||||
},
|
||||
});
|
||||
},
|
||||
*showDrawer({ payload }, { put }) {
|
||||
yield put({
|
||||
type: 'saveDrawer',
|
||||
payload,
|
||||
});
|
||||
},
|
||||
*loadDataScopeDrawer({ payload }, { call, put }) {
|
||||
const response = yield call(dataScopeList, payload);
|
||||
if (response.success) {
|
||||
yield put({
|
||||
type: 'saveLoadDataScopeDrawer',
|
||||
payload: {
|
||||
dataScope: {
|
||||
list: response.data.records,
|
||||
pagination: {
|
||||
total: response.data.total,
|
||||
current: response.data.current,
|
||||
pageSize: response.data.size,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
*loadDataScopeDict({ payload }, { call, put }) {
|
||||
const response = yield call(dict, payload);
|
||||
if (response.success) {
|
||||
yield put({
|
||||
type: 'saveDataScopeDict',
|
||||
payload: {
|
||||
dataScopeType: response.data,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
*submit({ payload }, { call }) {
|
||||
const response = yield call(submit, payload);
|
||||
if (response.success) {
|
||||
@ -245,6 +307,26 @@ export default {
|
||||
...newState,
|
||||
};
|
||||
},
|
||||
saveDrawer(state, action) {
|
||||
return {
|
||||
...state,
|
||||
drawer: action.payload,
|
||||
};
|
||||
},
|
||||
saveLoadDataScopeDrawer(state, action) {
|
||||
const newState = state;
|
||||
newState.drawer.dataScope = action.payload.dataScope;
|
||||
return {
|
||||
...newState,
|
||||
};
|
||||
},
|
||||
saveDataScopeDict(state, action) {
|
||||
const newState = state;
|
||||
newState.dict.dataScopeType = action.payload.dataScopeType;
|
||||
return {
|
||||
...newState,
|
||||
};
|
||||
},
|
||||
removeDetail(state) {
|
||||
return {
|
||||
...state,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { message } from 'antd';
|
||||
import router from 'umi/router';
|
||||
import { ROLE_NAMESPACE } from '../actions/role';
|
||||
import { list, submit, detail, remove, tree, grant } from '../services/role';
|
||||
import { list, submit, detail, remove, tree, treeById, grant } from '../services/role';
|
||||
import { grantTree, roleTreeKeys, dynamicRoutes, dynamicButtons } from '../services/menu';
|
||||
import { setButtons, setRoutes } from '../utils/authority';
|
||||
import { formatButtons, formatRoutes } from '../utils/utils';
|
||||
@ -17,8 +17,10 @@ export default {
|
||||
tree: [],
|
||||
},
|
||||
detail: {},
|
||||
grantTree: [],
|
||||
roleCheckedTreeKeys: [],
|
||||
menuGrantTree: [],
|
||||
menuTreeKeys: [],
|
||||
dataScopeGrantTree: [],
|
||||
dataScopeTreeKeys: [],
|
||||
},
|
||||
effects: {
|
||||
*fetchList({ payload }, { call, put }) {
|
||||
@ -44,6 +46,17 @@ export default {
|
||||
});
|
||||
}
|
||||
},
|
||||
*fetchInitById({ payload }, { call, put }) {
|
||||
const response = yield call(treeById, payload);
|
||||
if (response.success) {
|
||||
yield put({
|
||||
type: 'saveInit',
|
||||
payload: {
|
||||
tree: response.data,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
*fetchDetail({ payload }, { call, put }) {
|
||||
const response = yield call(detail, payload);
|
||||
if (response.success) {
|
||||
@ -66,7 +79,8 @@ export default {
|
||||
yield put({
|
||||
type: 'save',
|
||||
payload: {
|
||||
grantTree: response.data,
|
||||
menuGrantTree: response.data.menu,
|
||||
dataScopeGrantTree: response.data.dataScope,
|
||||
},
|
||||
});
|
||||
},
|
||||
@ -75,7 +89,8 @@ export default {
|
||||
yield put({
|
||||
type: 'save',
|
||||
payload: {
|
||||
roleCheckedTreeKeys: response.data,
|
||||
menuTreeKeys: response.data.menu,
|
||||
dataScopeTreeKeys: response.data.dataScope,
|
||||
},
|
||||
});
|
||||
},
|
||||
@ -83,7 +98,8 @@ export default {
|
||||
yield put({
|
||||
type: 'save',
|
||||
payload: {
|
||||
roleCheckedTreeKeys: payload.roleCheckedTreeKeys,
|
||||
menuTreeKeys: payload.menuTreeKeys,
|
||||
dataScopeTreeKeys: payload.dataScopeTreeKeys,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
158
src/pages/Authority/DataScope/DataScope.js
Normal file
158
src/pages/Authority/DataScope/DataScope.js
Normal file
@ -0,0 +1,158 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { connect } from 'dva';
|
||||
import { Drawer, Button, Col, Form, Input, Row } from 'antd';
|
||||
import Panel from '../../../components/Panel';
|
||||
import Grid from '../../../components/Sword/Grid';
|
||||
import {
|
||||
MENU_PARENT_LIST,
|
||||
MENU_LOAD_DATA_SCOPE_DRAWER,
|
||||
MENU_SHOW_DRAWER,
|
||||
} from '../../../actions/menu';
|
||||
import DataScopeCrud from './DataScopeCrud';
|
||||
import func from '../../../utils/Func';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
@connect(({ menu, loading }) => ({
|
||||
menu,
|
||||
loading: loading.models.menu,
|
||||
}))
|
||||
@Form.create()
|
||||
class DataScope extends PureComponent {
|
||||
showDrawer = (menuId, menuName, menuCode) => {
|
||||
const { dispatch } = this.props;
|
||||
dispatch(
|
||||
MENU_SHOW_DRAWER({
|
||||
visible: true,
|
||||
menuId,
|
||||
menuName,
|
||||
menuCode,
|
||||
})
|
||||
).then(() => {
|
||||
dispatch(MENU_LOAD_DATA_SCOPE_DRAWER({ menuId }));
|
||||
});
|
||||
};
|
||||
|
||||
onClose = () => {
|
||||
const { dispatch } = this.props;
|
||||
dispatch(
|
||||
MENU_SHOW_DRAWER({
|
||||
visible: false,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
// ============ 查询 ===============
|
||||
handleSearch = params => {
|
||||
const { dispatch } = this.props;
|
||||
dispatch(MENU_PARENT_LIST(params));
|
||||
};
|
||||
|
||||
// ============ 查询表单 ===============
|
||||
renderSearchForm = onReset => {
|
||||
const { form } = this.props;
|
||||
const { getFieldDecorator } = form;
|
||||
|
||||
return (
|
||||
<Row gutter={{ md: 8, lg: 24, xl: 48 }}>
|
||||
<Col md={8} sm={24}>
|
||||
<FormItem label="菜单编号">
|
||||
{getFieldDecorator('code')(<Input placeholder="请输入菜单编号" />)}
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col md={8} sm={24}>
|
||||
<FormItem label="菜单名称">
|
||||
{getFieldDecorator('name')(<Input placeholder="请输入菜单名称" />)}
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col>
|
||||
<div style={{ float: 'right' }}>
|
||||
<Button type="primary" htmlType="submit">
|
||||
查询
|
||||
</Button>
|
||||
<Button style={{ marginLeft: 8 }} onClick={onReset}>
|
||||
重置
|
||||
</Button>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
||||
// ============ 处理按钮点击回调事件 ===============
|
||||
handleBtnCallBack = payload => {
|
||||
const { btn, keys, rows } = payload;
|
||||
|
||||
if (btn.code === 'data_scope_setting') {
|
||||
this.showDrawer(keys[0], rows[0].name, rows[0].code);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const code = 'data_scope';
|
||||
|
||||
const {
|
||||
form,
|
||||
loading,
|
||||
menu: { data, drawer },
|
||||
} = this.props;
|
||||
|
||||
const { visible, menuName } = drawer;
|
||||
|
||||
const drawerTitle = func.isEmpty(menuName) ? '' : `[${menuName}]`;
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '菜单名称',
|
||||
dataIndex: 'name',
|
||||
},
|
||||
{
|
||||
title: '菜单编号',
|
||||
dataIndex: 'code',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '菜单别名',
|
||||
dataIndex: 'alias',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '路由地址',
|
||||
dataIndex: 'path',
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
dataIndex: 'sort',
|
||||
width: 60,
|
||||
align: 'right',
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Panel>
|
||||
<Grid
|
||||
code={code}
|
||||
form={form}
|
||||
onSearch={this.handleSearch}
|
||||
renderSearchForm={this.renderSearchForm}
|
||||
btnCallBack={this.handleBtnCallBack}
|
||||
loading={loading}
|
||||
data={data}
|
||||
columns={columns}
|
||||
actionColumnWidth={100}
|
||||
/>
|
||||
<Drawer
|
||||
title={`${drawerTitle} 数据权限配置`}
|
||||
placement="right"
|
||||
width={1000}
|
||||
closable={false}
|
||||
onClose={this.onClose}
|
||||
visible={visible}
|
||||
>
|
||||
<DataScopeCrud />
|
||||
</Drawer>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
}
|
||||
export default DataScope;
|
357
src/pages/Authority/DataScope/DataScopeCrud.js
Normal file
357
src/pages/Authority/DataScope/DataScopeCrud.js
Normal file
@ -0,0 +1,357 @@
|
||||
import React, { Fragment, PureComponent } from 'react';
|
||||
import { Button, Card, Col, Divider, Form, Input, message, Modal, Row, Select } from 'antd';
|
||||
import { connect } from 'dva';
|
||||
import Grid from '../../../components/Sword/Grid';
|
||||
import styles from '../../../layouts/Sword.less';
|
||||
import { submitDataScope, removeDataScope, scopeDataDetail } from '../../../services/menu';
|
||||
import func from '../../../utils/Func';
|
||||
import { MENU_LOAD_DATA_SCOPE_DICT, MENU_LOAD_DATA_SCOPE_DRAWER } from '../../../actions/menu';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const { TextArea } = Input;
|
||||
|
||||
@connect(({ menu, loading }) => ({
|
||||
menu,
|
||||
loading: loading.models.menu,
|
||||
}))
|
||||
@Form.create()
|
||||
class DataScopeCrud extends PureComponent {
|
||||
state = {
|
||||
stateVisible: false,
|
||||
viewMode: false,
|
||||
params: {},
|
||||
detail: {
|
||||
scopeType: 1,
|
||||
},
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
const {
|
||||
dispatch
|
||||
} = this.props;
|
||||
dispatch(MENU_LOAD_DATA_SCOPE_DICT());
|
||||
}
|
||||
|
||||
// ============ 查询 ===============
|
||||
handleSearch = params => {
|
||||
const {
|
||||
dispatch,
|
||||
menu: { drawer },
|
||||
} = this.props;
|
||||
const { menuId } = drawer;
|
||||
this.setState({ params });
|
||||
const search = { scopeName: params.scopeName, resourceCode: params.resourceCode, menuId};
|
||||
dispatch(MENU_LOAD_DATA_SCOPE_DRAWER(search));
|
||||
};
|
||||
|
||||
// ============ 查询表单 ===============
|
||||
renderSearchForm = onReset => {
|
||||
const { form } = this.props;
|
||||
const { getFieldDecorator } = form;
|
||||
|
||||
return (
|
||||
<Row gutter={{ md: 8, lg: 24, xl: 48 }}>
|
||||
<Col md={8} sm={24}>
|
||||
<FormItem label="权限名称">
|
||||
{getFieldDecorator('scopeName')(<Input placeholder="请输入权限名称" />)}
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col md={8} sm={24}>
|
||||
<FormItem label="权限编号">
|
||||
{getFieldDecorator('resourceCode')(<Input placeholder="请输入权限编号" />)}
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col>
|
||||
<div style={{ float: 'right' }}>
|
||||
<Button type="primary" htmlType="submit">
|
||||
查询
|
||||
</Button>
|
||||
<Button style={{ marginLeft: 8 }} onClick={onReset}>
|
||||
重置
|
||||
</Button>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
||||
handleSubmit = e => {
|
||||
e.preventDefault();
|
||||
const {
|
||||
form,
|
||||
menu: { drawer },
|
||||
} = this.props;
|
||||
const { menuId } = drawer;
|
||||
const {
|
||||
params,
|
||||
detail: { id },
|
||||
} = this.state;
|
||||
form.validateFieldsAndScroll((err, values) => {
|
||||
if (!err) {
|
||||
let formData = Object.assign(values, { menuId });
|
||||
if (!func.isEmpty(id)) {
|
||||
formData = Object.assign(values, { id });
|
||||
}
|
||||
submitDataScope(formData).then(resp => {
|
||||
if (resp.success) {
|
||||
message.success(resp.msg);
|
||||
} else {
|
||||
message.error(resp.msg || '提交失败');
|
||||
}
|
||||
this.handleSearch(params);
|
||||
this.handleStateCancel();
|
||||
form.resetFields();
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
handleStateCancel = () => {
|
||||
this.setState({
|
||||
stateVisible: false,
|
||||
viewMode: false,
|
||||
detail: { id: '' }
|
||||
});
|
||||
};
|
||||
|
||||
handleClick = (code, record) => {
|
||||
const {
|
||||
menu: { drawer },
|
||||
} = this.props;
|
||||
const { menuId, menuCode } = drawer;
|
||||
if (code === 'data_scope_add') {
|
||||
this.setState({
|
||||
stateVisible: true,
|
||||
detail: {
|
||||
id: '',
|
||||
menuId,
|
||||
resourceCode: menuCode,
|
||||
},
|
||||
});
|
||||
} else if (code === 'data_scope_edit') {
|
||||
const { id } = record;
|
||||
scopeDataDetail({ id }).then(resp => {
|
||||
if (resp.success) {
|
||||
this.setState({ stateVisible: true, viewMode: false, detail: resp.data });
|
||||
}
|
||||
});
|
||||
} else if (code === 'data_scope_view') {
|
||||
const { id } = record;
|
||||
scopeDataDetail({ id }).then(resp => {
|
||||
if (resp.success) {
|
||||
this.setState({ stateVisible: true, viewMode: true, detail: resp.data });
|
||||
}
|
||||
});
|
||||
} else if (code === 'data_scope_delete') {
|
||||
const { id } = record;
|
||||
const { params } = this.state;
|
||||
const refresh = this.handleSearch;
|
||||
Modal.confirm({
|
||||
title: '删除确认',
|
||||
content: '确定删除该条记录?',
|
||||
okText: '确定',
|
||||
okType: 'danger',
|
||||
cancelText: '取消',
|
||||
onOk() {
|
||||
removeDataScope({ ids: id }).then(resp => {
|
||||
if (resp.success) {
|
||||
message.success(resp.msg);
|
||||
refresh(params);
|
||||
} else {
|
||||
message.error(resp.msg || '删除失败');
|
||||
}
|
||||
});
|
||||
},
|
||||
onCancel() {},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
renderLeftButton = () => (
|
||||
<Button icon="plus" type="primary" onClick={() => this.handleClick('data_scope_add')}>
|
||||
新增
|
||||
</Button>
|
||||
);
|
||||
|
||||
render() {
|
||||
const {
|
||||
form,
|
||||
menu: { drawer, dict },
|
||||
loading,
|
||||
} = this.props;
|
||||
|
||||
const { stateVisible, viewMode, detail } = this.state;
|
||||
|
||||
const { getFieldDecorator } = form;
|
||||
|
||||
const { dataScope } = drawer;
|
||||
const { dataScopeType } = dict;
|
||||
|
||||
const formItemLayout = {
|
||||
labelCol: {
|
||||
span: 8,
|
||||
},
|
||||
wrapperCol: {
|
||||
span: 16,
|
||||
},
|
||||
};
|
||||
|
||||
const formAllItemLayout = {
|
||||
labelCol: {
|
||||
span: 4,
|
||||
},
|
||||
wrapperCol: {
|
||||
span: 20,
|
||||
},
|
||||
};
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '权限名称',
|
||||
dataIndex: 'scopeName',
|
||||
},
|
||||
{
|
||||
title: '权限编号',
|
||||
dataIndex: 'resourceCode',
|
||||
},
|
||||
{
|
||||
title: '权限字段',
|
||||
dataIndex: 'scopeColumn',
|
||||
},
|
||||
{
|
||||
title: '规则类型',
|
||||
dataIndex: 'scopeTypeName',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
render: (text, record) => (
|
||||
<Fragment>
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<Fragment key="edit">
|
||||
<a title="修改" onClick={() => this.handleClick('data_scope_edit', record)}>
|
||||
修改
|
||||
</a>
|
||||
</Fragment>
|
||||
<Divider type="vertical" />
|
||||
<Fragment key="delete">
|
||||
<a title="删除" onClick={() => this.handleClick('data_scope_delete', record)}>
|
||||
删除
|
||||
</a>
|
||||
</Fragment>
|
||||
<Divider type="vertical" />
|
||||
<Fragment key="view">
|
||||
<a title="查看" onClick={() => this.handleClick('data_scope_view', record)}>
|
||||
查看
|
||||
</a>
|
||||
</Fragment>
|
||||
</div>
|
||||
</Fragment>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Grid
|
||||
form={form}
|
||||
onSearch={this.handleSearch}
|
||||
renderSearchForm={this.renderSearchForm}
|
||||
renderLeftButton={this.renderLeftButton}
|
||||
loading={loading}
|
||||
data={dataScope}
|
||||
columns={columns}
|
||||
/>
|
||||
<Modal
|
||||
title="数据权限配置"
|
||||
width={1000}
|
||||
visible={stateVisible}
|
||||
onOk={this.handleSubmit}
|
||||
onCancel={this.handleStateCancel}
|
||||
>
|
||||
<Form style={{ marginTop: 8 }}>
|
||||
<Card className={styles.card} bordered={false}>
|
||||
<Row gutter={24}>
|
||||
<Col span={10}>
|
||||
<FormItem {...formItemLayout} label="权限名称">
|
||||
{getFieldDecorator('scopeName', {
|
||||
initialValue: detail.scopeName,
|
||||
})(<Input disabled={viewMode} placeholder="请输入权限名称" />)}
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span={10}>
|
||||
<FormItem {...formItemLayout} label="权限编号">
|
||||
{getFieldDecorator('resourceCode', {
|
||||
initialValue: detail.resourceCode,
|
||||
})(<Input disabled={viewMode} placeholder="请输入权限编号" />)}
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row gutter={24}>
|
||||
<Col span={10}>
|
||||
<FormItem {...formItemLayout} label="权限字段">
|
||||
{getFieldDecorator('scopeColumn', {
|
||||
initialValue: detail.scopeColumn,
|
||||
})(<Input disabled={viewMode} placeholder="请输入权限字段" />)}
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span={10}>
|
||||
<FormItem {...formItemLayout} label="规则类型">
|
||||
{getFieldDecorator('scopeType', {
|
||||
initialValue: detail.scopeType,
|
||||
})(
|
||||
<Select disabled={viewMode} placeholder="请选择规则类型">
|
||||
{dataScopeType.map(d => (
|
||||
<Select.Option key={d.dictKey} value={d.dictKey}>
|
||||
{d.dictValue}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
)}
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row gutter={24}>
|
||||
<Col span={20}>
|
||||
<FormItem {...formAllItemLayout} label="可见字段">
|
||||
{getFieldDecorator('scopeField', {
|
||||
initialValue: detail.scopeField,
|
||||
})(<Input disabled={viewMode} placeholder="请输入可见字段" />)}
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row gutter={24}>
|
||||
<Col span={20}>
|
||||
<FormItem {...formAllItemLayout} label="权限类名">
|
||||
{getFieldDecorator('scopeClass', {
|
||||
initialValue: detail.scopeClass,
|
||||
})(<Input disabled={viewMode} placeholder="请输入权限类名" />)}
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row gutter={24}>
|
||||
<Col span={20}>
|
||||
<FormItem {...formAllItemLayout} label="规则值">
|
||||
{getFieldDecorator('scopeValue', {
|
||||
initialValue: detail.scopeValue,
|
||||
})(<TextArea disabled={viewMode} rows={4} placeholder="请输入规则值" />)}
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row gutter={24}>
|
||||
<Col span={20}>
|
||||
<FormItem {...formAllItemLayout} label="备注">
|
||||
{getFieldDecorator('remark', {
|
||||
initialValue: detail.remark,
|
||||
})(<TextArea disabled={viewMode} rows={2} placeholder="请输入备注" />)}
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
</Form>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
export default DataScopeCrud;
|
@ -1,6 +1,6 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { connect } from 'dva';
|
||||
import { Button, Col, Form, Input, message, Modal, Row, Tree } from 'antd';
|
||||
import { Button, Col, Form, Input, message, Modal, Row, Tree, Tabs } from 'antd';
|
||||
import Panel from '../../../components/Panel';
|
||||
import Grid from '../../../components/Sword/Grid';
|
||||
import {
|
||||
@ -15,6 +15,7 @@ import { tenantMode } from '../../../defaultSettings';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const { TreeNode } = Tree;
|
||||
const { TabPane } = Tabs;
|
||||
|
||||
@connect(({ role, loading }) => ({
|
||||
role,
|
||||
@ -53,14 +54,9 @@ class Role extends PureComponent {
|
||||
// ========== 权限配置 =============
|
||||
handleGrant = () => {
|
||||
const {
|
||||
role: { roleCheckedTreeKeys },
|
||||
role: { menuTreeKeys, dataScopeTreeKeys },
|
||||
} = this.props;
|
||||
|
||||
if (roleCheckedTreeKeys.length === 0) {
|
||||
message.warn('权限未变更无需操作');
|
||||
return false;
|
||||
}
|
||||
|
||||
const keys = this.getSelectKeys();
|
||||
|
||||
this.setState({
|
||||
@ -69,14 +65,21 @@ class Role extends PureComponent {
|
||||
|
||||
const { dispatch } = this.props;
|
||||
dispatch(
|
||||
ROLE_GRANT({ roleIds: keys, menuIds: roleCheckedTreeKeys }, () => {
|
||||
this.setState({
|
||||
visible: false,
|
||||
confirmLoading: false,
|
||||
});
|
||||
message.success('配置成功');
|
||||
dispatch(MENU_REFRESH_DATA());
|
||||
})
|
||||
ROLE_GRANT(
|
||||
{
|
||||
roleIds: keys,
|
||||
menuIds: menuTreeKeys,
|
||||
dataScopeIds: dataScopeTreeKeys,
|
||||
},
|
||||
() => {
|
||||
this.setState({
|
||||
visible: false,
|
||||
confirmLoading: false,
|
||||
});
|
||||
message.success('配置成功');
|
||||
dispatch(MENU_REFRESH_DATA());
|
||||
}
|
||||
)
|
||||
);
|
||||
return true;
|
||||
};
|
||||
@ -100,15 +103,30 @@ class Role extends PureComponent {
|
||||
|
||||
handleCancel = () => {
|
||||
const { dispatch } = this.props;
|
||||
dispatch(ROLE_SET_TREE_KEYS({ roleCheckedTreeKeys: [] }));
|
||||
dispatch(ROLE_SET_TREE_KEYS({ menuTreeKeys: [], dataScopeTreeKeys: [], apiScopeTreeKeys: [] }));
|
||||
this.setState({
|
||||
visible: false,
|
||||
});
|
||||
};
|
||||
|
||||
onCheck = checkedTreeKeys => {
|
||||
const { dispatch } = this.props;
|
||||
dispatch(ROLE_SET_TREE_KEYS({ roleCheckedTreeKeys: checkedTreeKeys }));
|
||||
onMenuCheck = checkedTreeKeys => {
|
||||
const {
|
||||
dispatch,
|
||||
role: { dataScopeTreeKeys, apiScopeTreeKeys },
|
||||
} = this.props;
|
||||
dispatch(
|
||||
ROLE_SET_TREE_KEYS({ menuTreeKeys: checkedTreeKeys, dataScopeTreeKeys, apiScopeTreeKeys })
|
||||
);
|
||||
};
|
||||
|
||||
onDataScopeCheck = checkedTreeKeys => {
|
||||
const {
|
||||
dispatch,
|
||||
role: { menuTreeKeys, apiScopeTreeKeys },
|
||||
} = this.props;
|
||||
dispatch(
|
||||
ROLE_SET_TREE_KEYS({ dataScopeTreeKeys: checkedTreeKeys, menuTreeKeys, apiScopeTreeKeys })
|
||||
);
|
||||
};
|
||||
|
||||
// ============ 查询表单 ===============
|
||||
@ -173,7 +191,13 @@ class Role extends PureComponent {
|
||||
const {
|
||||
form,
|
||||
loading,
|
||||
role: { data, grantTree, roleCheckedTreeKeys },
|
||||
role: {
|
||||
data,
|
||||
menuGrantTree,
|
||||
menuTreeKeys,
|
||||
dataScopeGrantTree,
|
||||
dataScopeTreeKeys,
|
||||
},
|
||||
} = this.props;
|
||||
|
||||
const columns = [
|
||||
@ -214,7 +238,7 @@ class Role extends PureComponent {
|
||||
/>
|
||||
<Modal
|
||||
title="权限配置"
|
||||
width={350}
|
||||
width={380}
|
||||
visible={visible}
|
||||
confirmLoading={confirmLoading}
|
||||
onOk={this.handleGrant}
|
||||
@ -222,9 +246,18 @@ class Role extends PureComponent {
|
||||
okText="确认"
|
||||
cancelText="取消"
|
||||
>
|
||||
<Tree checkable checkedKeys={roleCheckedTreeKeys} onCheck={this.onCheck}>
|
||||
{this.renderTreeNodes(grantTree)}
|
||||
</Tree>
|
||||
<Tabs defaultActiveKey="1" size="small">
|
||||
<TabPane tab="菜单权限" key="1">
|
||||
<Tree checkable checkedKeys={menuTreeKeys} onCheck={this.onMenuCheck}>
|
||||
{this.renderTreeNodes(menuGrantTree)}
|
||||
</Tree>
|
||||
</TabPane>
|
||||
<TabPane tab="数据权限" key="2">
|
||||
<Tree checkable checkedKeys={dataScopeTreeKeys} onCheck={this.onDataScopeCheck}>
|
||||
{this.renderTreeNodes(dataScopeGrantTree)}
|
||||
</Tree>
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
</Modal>
|
||||
</Panel>
|
||||
);
|
@ -75,8 +75,8 @@ class RoleAdd extends PureComponent {
|
||||
);
|
||||
|
||||
return (
|
||||
<Panel title="新增" back="/system/role" action={action}>
|
||||
<Form hideRequiredMark style={{ marginTop: 8 }}>
|
||||
<Panel title="新增" back="/authority/role" action={action}>
|
||||
<Form style={{ marginTop: 8 }}>
|
||||
<Card title="基本信息" className={styles.card} bordered={false}>
|
||||
<Row gutter={24}>
|
||||
<Col span={10}>
|
@ -3,7 +3,7 @@ import { Form, Input, Card, Row, Col, Button, InputNumber, TreeSelect, message }
|
||||
import { connect } from 'dva';
|
||||
import Panel from '../../../components/Panel';
|
||||
import styles from '../../../layouts/Sword.less';
|
||||
import { ROLE_DETAIL, ROLE_INIT, ROLE_SUBMIT } from '../../../actions/role';
|
||||
import { ROLE_DETAIL, ROLE_INIT_BY_ID, ROLE_SUBMIT } from '../../../actions/role';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const { TextArea } = Input;
|
||||
@ -22,7 +22,7 @@ class RoleEdit extends PureComponent {
|
||||
},
|
||||
} = this.props;
|
||||
dispatch(ROLE_DETAIL(id));
|
||||
dispatch(ROLE_INIT());
|
||||
dispatch(ROLE_INIT_BY_ID(id));
|
||||
}
|
||||
|
||||
handleSubmit = e => {
|
||||
@ -90,8 +90,8 @@ class RoleEdit extends PureComponent {
|
||||
);
|
||||
|
||||
return (
|
||||
<Panel title="修改" back="/system/role" action={action}>
|
||||
<Form hideRequiredMark style={{ marginTop: 8 }}>
|
||||
<Panel title="修改" back="/authority/role" action={action}>
|
||||
<Form style={{ marginTop: 8 }}>
|
||||
<Card title="基本信息" className={styles.card} bordered={false}>
|
||||
<Row gutter={24}>
|
||||
<Col span={10}>
|
@ -29,7 +29,7 @@ class RoleView extends PureComponent {
|
||||
params: { id },
|
||||
},
|
||||
} = this.props;
|
||||
router.push(`/system/role/edit/${id}`);
|
||||
router.push(`/authority/role/edit/${id}`);
|
||||
};
|
||||
|
||||
render() {
|
||||
@ -62,8 +62,8 @@ class RoleView extends PureComponent {
|
||||
);
|
||||
|
||||
return (
|
||||
<Panel title="查看" back="/system/role" action={action}>
|
||||
<Form hideRequiredMark style={{ marginTop: 8 }}>
|
||||
<Panel title="查看" back="/authority/role" action={action}>
|
||||
<Form style={{ marginTop: 8 }}>
|
||||
<Card title="基本信息" className={styles.card} bordered={false}>
|
||||
<Row gutter={24}>
|
||||
<Col span={10}>
|
@ -20,14 +20,14 @@ class Workplace extends PureComponent {
|
||||
<Row gutter={24}>
|
||||
<Col span={24}>
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<img src="https://img.shields.io/badge/Release-V3.1.0-green.svg" alt="Downloads" />
|
||||
<img src="https://img.shields.io/badge/Release-V3.2.0-green.svg" alt="Downloads" />
|
||||
<img src="https://img.shields.io/badge/JDK-1.8+-green.svg" alt="Build Status" />
|
||||
<img
|
||||
src="https://img.shields.io/badge/Spring%20Cloud-2020-blue.svg"
|
||||
alt="Coverage Status"
|
||||
/>
|
||||
<img
|
||||
src="https://img.shields.io/badge/Spring%20Boot-2.5.2.RELEASE-blue.svg"
|
||||
src="https://img.shields.io/badge/Spring%20Boot-2.5.6.RELEASE-blue.svg"
|
||||
alt="Downloads"
|
||||
/>
|
||||
<a href="https://bladex.vip">
|
||||
@ -212,7 +212,24 @@ class Workplace extends PureComponent {
|
||||
</Row>
|
||||
<Row gutter={24}>
|
||||
<Card className={styles.card} bordered={false}>
|
||||
<Collapse bordered={false} defaultActiveKey={['26']}>
|
||||
<Collapse bordered={false} defaultActiveKey={['27']}>
|
||||
<Panel header="3.2.0发布 新增灵活数据权限特性" key="27">
|
||||
<div>1.升级 SpringBoot 至 2.5.6</div>
|
||||
<div>2.升级 SpringBootAdmin 至 2.5.3</div>
|
||||
<div>3.升级 SpringCloud 至 2020.0.4</div>
|
||||
<div>4.升级 Nacos 至 2.0.3</div>
|
||||
<div>5.升级 Knife4j 至 2.0.9</div>
|
||||
<div>6.升级 Mybatis-Plus 至 3.4.3.4</div>
|
||||
<div>7.新增注解配置数据权限特性</div>
|
||||
<div>8.新增Web在线配置数据权限特性</div>
|
||||
<div>9.新增自定义Sql配置数据权限特性</div>
|
||||
<div>10.新增懒加载表格树特性</div>
|
||||
<div>11.新增部门管理祖级节点字段</div>
|
||||
<div>12.新增CacheUtil工具类</div>
|
||||
<div>13.优化部门管理新增逻辑</div>
|
||||
<div>14.优化租户拦截器初始化逻辑</div>
|
||||
<div>15.优化适配各新版本API变动</div>
|
||||
</Panel>
|
||||
<Panel header="3.1.0发布 底层架构升级适配" key="26">
|
||||
<div>1.升级 SpringBoot 至 2.5.2</div>
|
||||
<div>2.升级 SpringBootAdmin 至 2.4.2</div>
|
||||
|
@ -16,6 +16,10 @@ export async function list(params) {
|
||||
return request(`/api/blade-system/menu/list?${stringify(params)}`);
|
||||
}
|
||||
|
||||
export async function parentList(params) {
|
||||
return request(`/api/blade-system/menu/menu-list?${stringify(params)}`);
|
||||
}
|
||||
|
||||
export async function tree(params) {
|
||||
return request(`/api/blade-system/menu/tree?${stringify(params)}`);
|
||||
}
|
||||
@ -49,3 +53,29 @@ export async function detail(params) {
|
||||
export async function routesAuthority() {
|
||||
return request('/api/blade-system/menu/auth-routes');
|
||||
}
|
||||
|
||||
export async function dataScopeList(params) {
|
||||
return request(`/api/blade-system/data-scope/list?${stringify(params)}`);
|
||||
}
|
||||
|
||||
export async function removeDataScope(params) {
|
||||
return request('/api/blade-system/data-scope/remove', {
|
||||
method: 'POST',
|
||||
body: func.toFormData(params),
|
||||
});
|
||||
}
|
||||
|
||||
export async function submitDataScope(params) {
|
||||
return request('/api/blade-system/data-scope/submit', {
|
||||
method: 'POST',
|
||||
body: params,
|
||||
});
|
||||
}
|
||||
|
||||
export async function scopeDataDetail(params) {
|
||||
return request(`/api/blade-system/data-scope/detail?${stringify(params)}`);
|
||||
}
|
||||
|
||||
export async function apiScopeList(params) {
|
||||
return request(`/api/blade-system/api-scope/list?${stringify(params)}`);
|
||||
}
|
||||
|
@ -12,6 +12,10 @@ export async function tree(params) {
|
||||
return request(`/api/blade-system/role/tree?${stringify(params)}`);
|
||||
}
|
||||
|
||||
export async function treeById(params) {
|
||||
return request(`/api/blade-system/role/tree-by-id?${stringify(params)}`);
|
||||
}
|
||||
|
||||
export async function grant(params) {
|
||||
return request('/api/blade-system/role/grant', {
|
||||
method: 'POST',
|
||||
|
Loading…
Reference in New Issue
Block a user