mirror of
https://github.com/chillzhuang/Sword
synced 2024-11-05 10:09:24 +08:00
🎉 升级为多租户系统
This commit is contained in:
parent
39baec4b69
commit
0c3b807ea4
@ -1,12 +1,15 @@
|
||||
## 简介
|
||||
Sword 是 [SpringBlade](https://gitee.com/smallc/SpringBlade)前端UI项目,基于react 、ant design、dva,用于快速构建系统中后台业务。
|
||||
|
||||
## 文档
|
||||
* 文档地址:[Sword开发手册](https://www.kancloud.cn/smallchill/sword)
|
||||
|
||||
## 官网
|
||||
* 官网地址:[https://bladex.vip](https://bladex.vip)
|
||||
|
||||
## 在线演示
|
||||
* Sword演示地址:[https://sword.bladex.vip](https://sword.bladex.vip)
|
||||
* Saber演示地址:[https://saber.avue.top](https://saber.avue.top)
|
||||
* Saber演示地址:[https://saber.bladex.vip](https://saber.bladex.vip)
|
||||
|
||||
## 后端项目地址
|
||||
* [Gitee地址](https://gitee.com/smallc/SpringBlade)
|
||||
|
@ -15,7 +15,7 @@ export default [
|
||||
path: '/',
|
||||
component: '../layouts/BasicLayout',
|
||||
Routes: ['src/pages/Authorized'],
|
||||
authority: ['admin', 'user'],
|
||||
authority: ['administrator', 'admin', 'user', 'test'],
|
||||
routes: [
|
||||
// dashboard
|
||||
{ path: '/', redirect: '/dashboard/workplace' },
|
||||
@ -156,6 +156,16 @@ export default [
|
||||
{ path: '/system/param/view/:id', component: './System/Param/ParamView' },
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/system/tenant',
|
||||
routes: [
|
||||
{ path: '/system/tenant', redirect: '/system/tenant/list' },
|
||||
{ path: '/system/tenant/list', component: './System/Tenant/Tenant' },
|
||||
{ path: '/system/tenant/add', component: './System/Tenant/TenantAdd' },
|
||||
{ path: '/system/tenant/edit/:id', component: './System/Tenant/TenantEdit' },
|
||||
{ path: '/system/tenant/view/:id', component: './System/Tenant/TenantView' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -6,18 +6,21 @@ function getFakeList(req, res) {
|
||||
data.push({
|
||||
id: '1',
|
||||
deptName: '刀锋科技',
|
||||
tenantCode: '000000',
|
||||
fullName: '江苏刀锋科技有限公司',
|
||||
sort: '1',
|
||||
children: [
|
||||
{
|
||||
id: '2',
|
||||
deptName: '常州刀锋',
|
||||
tenantCode: '000000',
|
||||
fullName: '常州刀锋科技有限公司',
|
||||
sort: '1',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
deptName: '南京刀锋',
|
||||
tenantCode: '000000',
|
||||
fullName: '南京刀锋科技有限公司',
|
||||
sort: '2',
|
||||
},
|
||||
@ -33,6 +36,7 @@ function getFakeDetail(req, res) {
|
||||
id: 2,
|
||||
parentId: 1,
|
||||
parentName: '江苏刀锋',
|
||||
tenantCode: '000000',
|
||||
deptName: '常州刀锋',
|
||||
fullName: '常州刀锋科技有限公司',
|
||||
sort: 1,
|
||||
|
42
mock/menu.js
42
mock/menu.js
@ -54,6 +54,11 @@ function getFakeRoutes(req, res) {
|
||||
code: 'param',
|
||||
name: '参数管理',
|
||||
},
|
||||
{
|
||||
path: '/system/tenant',
|
||||
code: 'tenant',
|
||||
name: '租户管理',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@ -397,6 +402,43 @@ function getFakeButtons(req, res) {
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
code: 'tenant',
|
||||
children: [
|
||||
{
|
||||
code: 'tenant_add',
|
||||
name: '新增',
|
||||
path: '/system/tenant/add',
|
||||
source: 'plus',
|
||||
action: 1,
|
||||
alias: 'add',
|
||||
},
|
||||
{
|
||||
code: 'tenant_edit',
|
||||
name: '修改',
|
||||
path: '/system/tenant/edit',
|
||||
source: 'form',
|
||||
action: 2,
|
||||
alias: 'edit',
|
||||
},
|
||||
{
|
||||
code: 'tenant_delete',
|
||||
name: '删除',
|
||||
path: '/api/blade-system/tenant/remove',
|
||||
source: 'delete',
|
||||
action: 3,
|
||||
alias: 'delete',
|
||||
},
|
||||
{
|
||||
code: 'tenant_view',
|
||||
name: '查看',
|
||||
path: '/system/tenant/view',
|
||||
source: 'file-text',
|
||||
action: 2,
|
||||
alias: 'view',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
code: 'log_usual',
|
||||
children: [
|
||||
|
@ -15,105 +15,105 @@ const proxy = {
|
||||
title: '博客标题1',
|
||||
categoryName: '批转通知',
|
||||
content: '博客内容1',
|
||||
date: '2018-05-08 12:00:00',
|
||||
releaseTime: '2018-05-08 12:00:00',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
title: '博客标题2',
|
||||
categoryName: '发布通知',
|
||||
content: '博客内容2',
|
||||
date: '2018-06-08 12:00:00',
|
||||
releaseTime: '2018-06-08 12:00:00',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
title: '博客标题3',
|
||||
categoryName: '任免通知',
|
||||
content: '博客内容3',
|
||||
date: '2018-07-08 12:00:00',
|
||||
releaseTime: '2018-07-08 12:00:00',
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
title: '博客标题4',
|
||||
categoryName: '指示通知',
|
||||
content: '博客内容4',
|
||||
date: '2018-08-08 12:00:00',
|
||||
releaseTime: '2018-08-08 12:00:00',
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
title: '博客标题5',
|
||||
categoryName: '转发通知',
|
||||
content: '博客内容5',
|
||||
date: '2018-09-08 12:00:00',
|
||||
releaseTime: '2018-09-08 12:00:00',
|
||||
},
|
||||
{
|
||||
id: '6',
|
||||
title: '博客标题1',
|
||||
categoryName: '批转通知',
|
||||
content: '博客内容1',
|
||||
date: '2018-05-08 12:00:00',
|
||||
releaseTime: '2018-05-08 12:00:00',
|
||||
},
|
||||
{
|
||||
id: '7',
|
||||
title: '博客标题2',
|
||||
categoryName: '发布通知',
|
||||
content: '博客内容2',
|
||||
date: '2018-06-08 12:00:00',
|
||||
releaseTime: '2018-06-08 12:00:00',
|
||||
},
|
||||
{
|
||||
id: '8',
|
||||
title: '博客标题3',
|
||||
categoryName: '任免通知',
|
||||
content: '博客内容3',
|
||||
date: '2018-07-08 12:00:00',
|
||||
releaseTime: '2018-07-08 12:00:00',
|
||||
},
|
||||
{
|
||||
id: '9',
|
||||
title: '博客标题4',
|
||||
categoryName: '指示通知',
|
||||
content: '博客内容4',
|
||||
date: '2018-08-08 12:00:00',
|
||||
releaseTime: '2018-08-08 12:00:00',
|
||||
},
|
||||
{
|
||||
id: '10',
|
||||
title: '博客标题5',
|
||||
categoryName: '转发通知',
|
||||
content: '博客内容5',
|
||||
date: '2018-09-08 12:00:00',
|
||||
releaseTime: '2018-09-08 12:00:00',
|
||||
},
|
||||
{
|
||||
id: '11',
|
||||
title: '博客标题1',
|
||||
categoryName: '批转通知',
|
||||
content: '博客内容1',
|
||||
date: '2018-05-08 12:00:00',
|
||||
releaseTime: '2018-05-08 12:00:00',
|
||||
},
|
||||
{
|
||||
id: '12',
|
||||
title: '博客标题2',
|
||||
categoryName: '发布通知',
|
||||
content: '博客内容2',
|
||||
date: '2018-06-08 12:00:00',
|
||||
releaseTime: '2018-06-08 12:00:00',
|
||||
},
|
||||
{
|
||||
id: '13',
|
||||
title: '博客标题3',
|
||||
categoryName: '任免通知',
|
||||
content: '博客内容3',
|
||||
date: '2018-07-08 12:00:00',
|
||||
releaseTime: '2018-07-08 12:00:00',
|
||||
},
|
||||
{
|
||||
id: '14',
|
||||
title: '博客标题4',
|
||||
categoryName: '指示通知',
|
||||
content: '博客内容4',
|
||||
date: '2018-08-08 12:00:00',
|
||||
releaseTime: '2018-08-08 12:00:00',
|
||||
},
|
||||
{
|
||||
id: '15',
|
||||
title: '博客标题5',
|
||||
categoryName: '转发通知',
|
||||
content: '博客内容5',
|
||||
date: '2018-09-08 12:00:00',
|
||||
releaseTime: '2018-09-08 12:00:00',
|
||||
},
|
||||
],
|
||||
},
|
||||
@ -138,7 +138,7 @@ const proxy = {
|
||||
title: '通知标题详情',
|
||||
category: '3',
|
||||
categoryName: '转发通知',
|
||||
date: '2018-12-31 23:33:33',
|
||||
releaseTime: '2018-12-31 23:33:33',
|
||||
content: '通知公告内容详情',
|
||||
},
|
||||
message: 'success',
|
||||
|
@ -7,12 +7,14 @@ function getFakeList(req, res) {
|
||||
{
|
||||
id: '1',
|
||||
roleName: '超级管理员',
|
||||
tenantCode: '000000',
|
||||
roleAlias: 'administrator',
|
||||
sort: '1',
|
||||
children: [
|
||||
{
|
||||
id: '2',
|
||||
roleName: '管理员',
|
||||
tenantCode: '000001',
|
||||
roleAlias: 'admin',
|
||||
sort: '1',
|
||||
},
|
||||
@ -21,18 +23,21 @@ function getFakeList(req, res) {
|
||||
{
|
||||
id: '3',
|
||||
roleName: '用户',
|
||||
tenantCode: '000002',
|
||||
roleAlias: 'user',
|
||||
sort: '2',
|
||||
children: [
|
||||
{
|
||||
id: '4',
|
||||
roleName: '普通用户',
|
||||
tenantCode: '000003',
|
||||
roleAlias: 'user',
|
||||
sort: '1',
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
roleName: '访客',
|
||||
tenantCode: '000004',
|
||||
roleAlias: 'guest',
|
||||
sort: '2',
|
||||
},
|
||||
@ -49,6 +54,7 @@ function getFakeDetail(req, res) {
|
||||
id: 2,
|
||||
parentId: 1,
|
||||
parentName: '超级管理员',
|
||||
tenantCode: '000000',
|
||||
roleName: '用户',
|
||||
roleAlias: 'user',
|
||||
sort: 1,
|
||||
|
75
mock/tenant.js
Normal file
75
mock/tenant.js
Normal file
@ -0,0 +1,75 @@
|
||||
import { delay } from 'roadhog-api-doc';
|
||||
|
||||
function getFakeList(req, res) {
|
||||
const json = { code: 200, success: true, msg: '操作成功' };
|
||||
const list = [];
|
||||
list.push(
|
||||
{
|
||||
id: '1',
|
||||
tenantCode: '000000',
|
||||
tenantName: '管理组',
|
||||
linkman: 'Chill',
|
||||
contactNumber: '66666666666',
|
||||
address: '管理组地址',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
tenantCode: '000001',
|
||||
tenantName: '用户组',
|
||||
linkman: 'Bill',
|
||||
contactNumber: '23333333333',
|
||||
address: '用户组地址',
|
||||
}
|
||||
);
|
||||
json.data = {
|
||||
total: 10,
|
||||
size: 10,
|
||||
current: 2,
|
||||
searchCount: true,
|
||||
pages: 1,
|
||||
records: list,
|
||||
};
|
||||
return res.json(json);
|
||||
}
|
||||
|
||||
function getFakeDetail(req, res) {
|
||||
const json = { code: 200, success: true, msg: '操作成功' };
|
||||
json.data = {
|
||||
id: '1',
|
||||
tenantCode: '000000',
|
||||
tenantName: '管理组',
|
||||
linkman: 'Chill',
|
||||
contactNumber: '66666666666',
|
||||
address: '管理组地址',
|
||||
};
|
||||
return res.json(json);
|
||||
}
|
||||
|
||||
function fakeSuccess(req, res) {
|
||||
const json = { code: 200, success: true, msg: '操作成功' };
|
||||
return res.json(json);
|
||||
}
|
||||
|
||||
function getFakeTenantSelect(req, res) {
|
||||
const json = { code: 200, success: true, msg: '操作成功' };
|
||||
json.data = [
|
||||
{
|
||||
tenantCode: '000000',
|
||||
tenantName: '管理组',
|
||||
},
|
||||
{
|
||||
tenantCode: '000001',
|
||||
tenantName: '用户组',
|
||||
},
|
||||
];
|
||||
return res.json(json);
|
||||
}
|
||||
|
||||
const proxy = {
|
||||
'GET /api/blade-system/tenant/list': getFakeList,
|
||||
'GET /api/blade-system/tenant/select': getFakeTenantSelect,
|
||||
'GET /api/blade-system/tenant/detail': getFakeDetail,
|
||||
'POST /api/blade-system/tenant/submit': fakeSuccess,
|
||||
'POST /api/blade-system/tenant/remove': fakeSuccess,
|
||||
};
|
||||
export default delay(proxy, 500);
|
@ -6,6 +6,7 @@ function getFakeList(req, res) {
|
||||
list.push(
|
||||
{
|
||||
id: '1',
|
||||
tenantCode: '000000',
|
||||
account: 'admin',
|
||||
name: '超级管理员',
|
||||
realName: '管理员',
|
||||
@ -17,6 +18,7 @@ function getFakeList(req, res) {
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
tenantCode: '000001',
|
||||
account: 'user',
|
||||
name: '系统用户',
|
||||
realName: '用户',
|
||||
@ -40,8 +42,9 @@ function getFakeList(req, res) {
|
||||
|
||||
function getFakeDetail(req, res) {
|
||||
const json = { code: 200, success: true, msg: '操作成功' };
|
||||
const detail = {
|
||||
json.data = {
|
||||
id: '1',
|
||||
tenantCode: '000000',
|
||||
account: 'admin',
|
||||
name: '超级管理员',
|
||||
realName: '管理员',
|
||||
@ -56,7 +59,6 @@ function getFakeDetail(req, res) {
|
||||
birthday: '2018-12-31 23:33:33',
|
||||
statusName: '启用',
|
||||
};
|
||||
json.data = detail;
|
||||
return res.json(json);
|
||||
}
|
||||
|
||||
|
36
src/actions/tenant.js
Normal file
36
src/actions/tenant.js
Normal file
@ -0,0 +1,36 @@
|
||||
export const TENANT_NAMESPACE = 'tenant';
|
||||
|
||||
export function TENANT_LIST(payload) {
|
||||
return {
|
||||
type: `${TENANT_NAMESPACE}/fetchList`,
|
||||
payload,
|
||||
};
|
||||
}
|
||||
|
||||
export function TENANT_DETAIL(id) {
|
||||
return {
|
||||
type: `${TENANT_NAMESPACE}/fetchDetail`,
|
||||
payload: { id },
|
||||
};
|
||||
}
|
||||
|
||||
export function TENANT_CLEAR_DETAIL() {
|
||||
return {
|
||||
type: `${TENANT_NAMESPACE}/clearDetail`,
|
||||
payload: {},
|
||||
};
|
||||
}
|
||||
|
||||
export function TENANT_SUBMIT(payload) {
|
||||
return {
|
||||
type: `${TENANT_NAMESPACE}/submit`,
|
||||
payload,
|
||||
};
|
||||
}
|
||||
|
||||
export function TENANT_REMOVE(payload) {
|
||||
return {
|
||||
type: `${TENANT_NAMESPACE}/remove`,
|
||||
payload,
|
||||
};
|
||||
}
|
@ -14,6 +14,13 @@ export function USER_INIT() {
|
||||
};
|
||||
}
|
||||
|
||||
export function USER_CHANGE_INIT(payload) {
|
||||
return {
|
||||
type: `${USER_NAMESPACE}/fetchChangeInit`,
|
||||
payload,
|
||||
};
|
||||
}
|
||||
|
||||
export function USER_DETAIL(id) {
|
||||
return {
|
||||
type: `${USER_NAMESPACE}/fetchDetail`,
|
||||
|
1
src/components/Login/index.d.ts
vendored
1
src/components/Login/index.d.ts
vendored
@ -12,6 +12,7 @@ export interface ILoginProps {
|
||||
|
||||
export default class Login extends React.Component<ILoginProps, any> {
|
||||
public static Tab: typeof LoginTab;
|
||||
public static TenantCode: typeof LoginItem;
|
||||
public static UserName: typeof LoginItem;
|
||||
public static Password: typeof LoginItem;
|
||||
public static Mobile: typeof LoginItem;
|
||||
|
@ -3,6 +3,20 @@ import { Icon } from 'antd';
|
||||
import styles from './index.less';
|
||||
|
||||
export default {
|
||||
TenantCode: {
|
||||
props: {
|
||||
size: 'large',
|
||||
id: 'tenantCode',
|
||||
prefix: <Icon type="home" className={styles.prefixIcon} />,
|
||||
placeholder: 'admin',
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: 'Please enter tenantcode!',
|
||||
},
|
||||
],
|
||||
},
|
||||
UserName: {
|
||||
props: {
|
||||
size: 'large',
|
||||
|
@ -30,11 +30,11 @@ export default class ToolBar extends PureComponent {
|
||||
</Button>
|
||||
))}
|
||||
{renderLeftButton ? renderLeftButton() : null}
|
||||
</div>
|
||||
{renderRightButton ? (
|
||||
<div style={{ float: 'right', marginRight: '20px' }}>renderRightButton()</div>
|
||||
<div style={{ float: 'right', marginRight: '20px' }}>{renderRightButton()}</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -51,10 +51,12 @@ const UserLayout = ({ children }) => (
|
||||
<div className={styles.header}>
|
||||
<Link to="/">
|
||||
<img alt="logo" className={styles.logo} src={logo} />
|
||||
<span className={styles.title}>Ant Design</span>
|
||||
<span className={styles.title}>Sword 企业级开发平台</span>
|
||||
</Link>
|
||||
</div>
|
||||
<div className={styles.desc}>Ant Design 是西湖区最具影响力的 Web 设计规范</div>
|
||||
<div className={styles.desc}>
|
||||
Sword是SpringBlade前端UI项目,基于react 、ant design、umi、dva等流行技术栈。
|
||||
</div>
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
|
@ -1,4 +1,5 @@
|
||||
export default {
|
||||
'app.login.tenantCode': 'tenantCode',
|
||||
'app.login.userName': 'userName',
|
||||
'app.login.password': 'password',
|
||||
'app.login.message-invalid-credentials': 'Invalid username or password(admin/ant.design)',
|
||||
@ -20,6 +21,7 @@ export default {
|
||||
'app.register-result.view-mailbox': 'View mailbox',
|
||||
'validation.email.required': 'Please enter your email!',
|
||||
'validation.email.wrong-format': 'The email address is in the wrong format!',
|
||||
'validation.userName.tenantCode': 'Please enter your tenantCode!',
|
||||
'validation.userName.required': 'Please enter your userName!',
|
||||
'validation.password.required': 'Please enter your password!',
|
||||
'validation.password.twice': 'The passwords entered twice do not match!',
|
||||
|
@ -13,6 +13,7 @@ export default {
|
||||
'menu.system.menu': 'menu',
|
||||
'menu.system.role': 'role',
|
||||
'menu.system.param': 'parameter',
|
||||
'menu.system.tenant': 'tenant',
|
||||
'menu.monitor': 'monitor',
|
||||
'menu.monitor.log': 'log',
|
||||
'menu.monitor.log.log_usual': 'usual log',
|
||||
|
@ -1,4 +1,5 @@
|
||||
export default {
|
||||
'app.login.tenantCode': '租户编号',
|
||||
'app.login.userName': '用户名',
|
||||
'app.login.password': '密码',
|
||||
'app.login.message-invalid-credentials': '账户或密码错误(admin/ant.design)',
|
||||
@ -20,6 +21,7 @@ export default {
|
||||
'app.register-result.view-mailbox': '查看邮箱',
|
||||
'validation.email.required': '请输入邮箱地址!',
|
||||
'validation.email.wrong-format': '邮箱地址格式错误!',
|
||||
'validation.tenantCode.required': '请输入租户编号!',
|
||||
'validation.userName.required': '请输入用户名!',
|
||||
'validation.password.required': '请输入密码!',
|
||||
'validation.password.twice': '两次输入的密码不匹配!',
|
||||
|
@ -13,6 +13,7 @@ export default {
|
||||
'menu.system.menu': '菜单管理',
|
||||
'menu.system.role': '角色管理',
|
||||
'menu.system.param': '参数管理',
|
||||
'menu.system.tenant': '租户管理',
|
||||
'menu.monitor': '系统监控',
|
||||
'menu.monitor.log': '日志管理',
|
||||
'menu.monitor.log.log_usual': '通用日志',
|
||||
|
@ -1,4 +1,5 @@
|
||||
export default {
|
||||
'app.login.tenantCode': '租戶編號',
|
||||
'app.login.userName': '賬戶',
|
||||
'app.login.password': '密碼',
|
||||
'app.login.message-invalid-credentials': '賬戶或密碼錯誤(admin/ant.design)',
|
||||
@ -20,6 +21,7 @@ export default {
|
||||
'app.register-result.view-mailbox': '查看郵箱',
|
||||
'validation.email.required': '請輸入郵箱地址!',
|
||||
'validation.email.wrong-format': '郵箱地址格式錯誤!',
|
||||
'validation.tenantCode.required': '請輸入租戶編號!',
|
||||
'validation.userName.required': '請輸入賬戶!',
|
||||
'validation.password.required': '請輸入密碼!',
|
||||
'validation.password.twice': '兩次輸入的密碼不匹配!',
|
||||
|
@ -13,6 +13,7 @@ export default {
|
||||
'menu.system.menu': '菜單管理',
|
||||
'menu.system.role': '角色管理',
|
||||
'menu.system.param': '參數管理',
|
||||
'menu.system.tenant': '租戶管理',
|
||||
'menu.monitor': '系統監控',
|
||||
'menu.monitor.log': '日志管理',
|
||||
'menu.monitor.log.log_usual': '通用日志',
|
||||
|
@ -18,6 +18,94 @@ import { getRoutes, setRoutes, getButtons, setButtons } from '../utils/authority
|
||||
import { MENU_NAMESPACE } from '../actions/menu';
|
||||
import { formatRoutes, formatButtons } from '../utils/utils';
|
||||
|
||||
const { check } = Authorized;
|
||||
|
||||
// Conversion router to menu.
|
||||
function formatter(data, parentAuthority, parentName) {
|
||||
return data
|
||||
.map(item => {
|
||||
if (!item.name || !item.path) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let locale = 'menu';
|
||||
if (parentName) {
|
||||
locale = `${parentName}.${item.name}`;
|
||||
} else {
|
||||
locale = `menu.${item.name}`;
|
||||
}
|
||||
// if enableMenuLocale use item.name,
|
||||
// close menu international
|
||||
const name = menu.disableLocal
|
||||
? item.name
|
||||
: formatMessage({ id: locale, defaultMessage: item.name });
|
||||
const result = {
|
||||
...item,
|
||||
name,
|
||||
locale,
|
||||
authority: item.authority || parentAuthority,
|
||||
};
|
||||
if (item.routes) {
|
||||
const children = formatter(item.routes, item.authority, locale);
|
||||
// Reduce memory usage
|
||||
result.children = children;
|
||||
}
|
||||
delete result.routes;
|
||||
return result;
|
||||
})
|
||||
.filter(item => item);
|
||||
}
|
||||
|
||||
const memoizeOneFormatter = memoizeOne(formatter, isEqual);
|
||||
|
||||
/**
|
||||
* get SubMenu or Item
|
||||
*/
|
||||
const getSubMenu = item => {
|
||||
// doc: add hideChildrenInMenu
|
||||
if (item.children && !item.hideChildrenInMenu && item.children.some(child => child.name)) {
|
||||
return {
|
||||
...item,
|
||||
children: filterMenuData(item.children), // eslint-disable-line
|
||||
};
|
||||
}
|
||||
return item;
|
||||
};
|
||||
|
||||
/**
|
||||
* filter menuData
|
||||
*/
|
||||
const filterMenuData = menuData => {
|
||||
if (!menuData) {
|
||||
return [];
|
||||
}
|
||||
return menuData
|
||||
.filter(item => item.name && !item.hideInMenu)
|
||||
.map(item => check(item.authority, getSubMenu(item)))
|
||||
.filter(item => item);
|
||||
};
|
||||
/**
|
||||
* 获取面包屑映射
|
||||
* @param {Object} menuData 菜单配置
|
||||
*/
|
||||
const getBreadcrumbNameMap = menuData => {
|
||||
const routerMap = {};
|
||||
|
||||
const flattenMenuData = data => {
|
||||
data.forEach(menuItem => {
|
||||
if (menuItem.children) {
|
||||
flattenMenuData(menuItem.children);
|
||||
}
|
||||
// Reduce memory usage
|
||||
routerMap[menuItem.path] = menuItem;
|
||||
});
|
||||
};
|
||||
flattenMenuData(menuData);
|
||||
return routerMap;
|
||||
};
|
||||
|
||||
const memoizeOneGetBreadcrumbNameMap = memoizeOne(getBreadcrumbNameMap, isEqual);
|
||||
|
||||
export default {
|
||||
namespace: MENU_NAMESPACE,
|
||||
|
||||
@ -165,91 +253,3 @@ export default {
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const { check } = Authorized;
|
||||
|
||||
// Conversion router to menu.
|
||||
function formatter(data, parentAuthority, parentName) {
|
||||
return data
|
||||
.map(item => {
|
||||
if (!item.name || !item.path) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let locale = 'menu';
|
||||
if (parentName) {
|
||||
locale = `${parentName}.${item.name}`;
|
||||
} else {
|
||||
locale = `menu.${item.name}`;
|
||||
}
|
||||
// if enableMenuLocale use item.name,
|
||||
// close menu international
|
||||
const name = menu.disableLocal
|
||||
? item.name
|
||||
: formatMessage({ id: locale, defaultMessage: item.name });
|
||||
const result = {
|
||||
...item,
|
||||
name,
|
||||
locale,
|
||||
authority: item.authority || parentAuthority,
|
||||
};
|
||||
if (item.routes) {
|
||||
const children = formatter(item.routes, item.authority, locale);
|
||||
// Reduce memory usage
|
||||
result.children = children;
|
||||
}
|
||||
delete result.routes;
|
||||
return result;
|
||||
})
|
||||
.filter(item => item);
|
||||
}
|
||||
|
||||
const memoizeOneFormatter = memoizeOne(formatter, isEqual);
|
||||
|
||||
/**
|
||||
* get SubMenu or Item
|
||||
*/
|
||||
const getSubMenu = item => {
|
||||
// doc: add hideChildrenInMenu
|
||||
if (item.children && !item.hideChildrenInMenu && item.children.some(child => child.name)) {
|
||||
return {
|
||||
...item,
|
||||
children: filterMenuData(item.children), // eslint-disable-line
|
||||
};
|
||||
}
|
||||
return item;
|
||||
};
|
||||
|
||||
/**
|
||||
* filter menuData
|
||||
*/
|
||||
const filterMenuData = menuData => {
|
||||
if (!menuData) {
|
||||
return [];
|
||||
}
|
||||
return menuData
|
||||
.filter(item => item.name && !item.hideInMenu)
|
||||
.map(item => check(item.authority, getSubMenu(item)))
|
||||
.filter(item => item);
|
||||
};
|
||||
/**
|
||||
* 获取面包屑映射
|
||||
* @param {Object} menuData 菜单配置
|
||||
*/
|
||||
const getBreadcrumbNameMap = menuData => {
|
||||
const routerMap = {};
|
||||
|
||||
const flattenMenuData = data => {
|
||||
data.forEach(menuItem => {
|
||||
if (menuItem.children) {
|
||||
flattenMenuData(menuItem.children);
|
||||
}
|
||||
// Reduce memory usage
|
||||
routerMap[menuItem.path] = menuItem;
|
||||
});
|
||||
};
|
||||
flattenMenuData(menuData);
|
||||
return routerMap;
|
||||
};
|
||||
|
||||
const memoizeOneGetBreadcrumbNameMap = memoizeOne(getBreadcrumbNameMap, isEqual);
|
||||
|
87
src/models/tenant.js
Normal file
87
src/models/tenant.js
Normal file
@ -0,0 +1,87 @@
|
||||
import { message } from 'antd';
|
||||
import router from 'umi/router';
|
||||
import { TENANT_NAMESPACE } from '../actions/tenant';
|
||||
import { list, submit, detail, remove } from '../services/tenant';
|
||||
|
||||
export default {
|
||||
namespace: TENANT_NAMESPACE,
|
||||
state: {
|
||||
data: {
|
||||
list: [],
|
||||
pagination: false,
|
||||
},
|
||||
detail: {},
|
||||
},
|
||||
effects: {
|
||||
*fetchList({ payload }, { call, put }) {
|
||||
const response = yield call(list, payload);
|
||||
if (response.success) {
|
||||
yield put({
|
||||
type: 'saveList',
|
||||
payload: {
|
||||
list: response.data.records,
|
||||
pagination: {
|
||||
total: response.data.total,
|
||||
current: response.data.current,
|
||||
pageSize: response.data.size,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
*fetchDetail({ payload }, { call, put }) {
|
||||
const response = yield call(detail, payload);
|
||||
if (response.success) {
|
||||
yield put({
|
||||
type: 'saveDetail',
|
||||
payload: {
|
||||
detail: response.data,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
*clearDetail({ payload }, { put }) {
|
||||
yield put({
|
||||
type: 'removeDetail',
|
||||
payload: { payload },
|
||||
});
|
||||
},
|
||||
*submit({ payload }, { call }) {
|
||||
const response = yield call(submit, payload);
|
||||
if (response.success) {
|
||||
message.success('提交成功');
|
||||
router.push('/system/tenant');
|
||||
}
|
||||
},
|
||||
*remove({ payload }, { call }) {
|
||||
const {
|
||||
data: { keys },
|
||||
success,
|
||||
} = payload;
|
||||
const response = yield call(remove, { ids: keys });
|
||||
if (response.success) {
|
||||
success();
|
||||
}
|
||||
},
|
||||
},
|
||||
reducers: {
|
||||
saveList(state, action) {
|
||||
return {
|
||||
...state,
|
||||
data: action.payload,
|
||||
};
|
||||
},
|
||||
saveDetail(state, action) {
|
||||
return {
|
||||
...state,
|
||||
detail: action.payload.detail,
|
||||
};
|
||||
},
|
||||
removeDetail(state) {
|
||||
return {
|
||||
...state,
|
||||
detail: {},
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
@ -2,6 +2,7 @@ import { message } from 'antd';
|
||||
import router from 'umi/router';
|
||||
import { USER_NAMESPACE } from '../actions/user';
|
||||
import { query as queryUsers, list, submit, detail, remove, grant } from '../services/user';
|
||||
import { select as tenants } from '../services/tenant';
|
||||
import { tree as roles } from '../services/role';
|
||||
import { tree as depts } from '../services/dept';
|
||||
import { getCurrentUser } from '../utils/authority';
|
||||
@ -19,6 +20,7 @@ export default {
|
||||
init: {
|
||||
roleTree: [],
|
||||
deptTree: [],
|
||||
tenantList: [],
|
||||
},
|
||||
detail: {},
|
||||
},
|
||||
@ -57,9 +59,24 @@ export default {
|
||||
*fetchInit({ payload }, { call, put }) {
|
||||
const responseRole = yield call(roles, payload);
|
||||
const responseDept = yield call(depts, payload);
|
||||
if (responseRole.success && responseDept.success) {
|
||||
const responseTenant = yield call(tenants, payload);
|
||||
if (responseRole.success && responseDept.success && responseTenant.success) {
|
||||
yield put({
|
||||
type: 'saveInit',
|
||||
payload: {
|
||||
roleTree: responseRole.data,
|
||||
deptTree: responseDept.data,
|
||||
tenantList: responseTenant.data,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
*fetchChangeInit({ payload }, { call, put }) {
|
||||
const responseRole = yield call(roles, payload);
|
||||
const responseDept = yield call(depts, payload);
|
||||
if (responseRole.success && responseDept.success) {
|
||||
yield put({
|
||||
type: 'saveChangeInit',
|
||||
payload: {
|
||||
roleTree: responseRole.data,
|
||||
deptTree: responseDept.data,
|
||||
@ -146,6 +163,14 @@ export default {
|
||||
init: action.payload,
|
||||
};
|
||||
},
|
||||
saveChangeInit(state, action) {
|
||||
const newState = state;
|
||||
newState.init.roleTree = action.payload.roleTree;
|
||||
newState.init.deptTree = action.payload.deptTree;
|
||||
return {
|
||||
...newState,
|
||||
};
|
||||
},
|
||||
saveDetail(state, action) {
|
||||
return {
|
||||
...state,
|
||||
|
@ -122,7 +122,7 @@ class Notice extends PureComponent {
|
||||
},
|
||||
{
|
||||
title: formatMessage({ id: 'desk.notice.date' }),
|
||||
dataIndex: 'date',
|
||||
dataIndex: 'releaseTime',
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -29,7 +29,7 @@ class NoticeAdd extends PureComponent {
|
||||
|
||||
const params = {
|
||||
...values,
|
||||
date: func.format(values.date),
|
||||
releaseTime: func.format(values.releaseTime),
|
||||
};
|
||||
|
||||
dispatch(NOTICE_SUBMIT(params));
|
||||
@ -100,7 +100,7 @@ class NoticeAdd extends PureComponent {
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label={<FormattedMessage id="desk.notice.date" />}>
|
||||
{getFieldDecorator('date', {
|
||||
{getFieldDecorator('releaseTime', {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
|
@ -41,7 +41,7 @@ class NoticeAdd extends PureComponent {
|
||||
const params = {
|
||||
id,
|
||||
...values,
|
||||
date: func.format(values.date),
|
||||
releaseTime: func.format(values.releaseTime),
|
||||
};
|
||||
dispatch(NOTICE_SUBMIT(params));
|
||||
});
|
||||
@ -113,14 +113,14 @@ class NoticeAdd extends PureComponent {
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label={<FormattedMessage id="desk.notice.date" />}>
|
||||
{getFieldDecorator('date', {
|
||||
{getFieldDecorator('releaseTime', {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: formatMessage({ id: 'desk.notice.date.validation' }),
|
||||
},
|
||||
],
|
||||
initialValue: moment(detail.date, 'YYYY-MM-DD HH:mm:ss'),
|
||||
initialValue: moment(detail.releaseTime, 'YYYY-MM-DD HH:mm:ss'),
|
||||
})(
|
||||
<DatePicker
|
||||
style={{ width: '100%' }}
|
||||
|
@ -66,7 +66,7 @@ class NoticeAdd extends PureComponent {
|
||||
<span>{detail.categoryName}</span>
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label={<FormattedMessage id="desk.notice.date" />}>
|
||||
<span>{detail.date}</span>
|
||||
<span>{detail.releaseTime}</span>
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label={<FormattedMessage id="desk.notice.content" />}>
|
||||
<span>{detail.content}</span>
|
||||
|
@ -2,10 +2,10 @@ import React, { Component } from 'react';
|
||||
import { connect } from 'dva';
|
||||
import { formatMessage, FormattedMessage } from 'umi/locale';
|
||||
import { Checkbox, Alert } from 'antd';
|
||||
import Login from '@/components/Login';
|
||||
import Login from '../../components/Login';
|
||||
import styles from './Login.less';
|
||||
|
||||
const { Tab, UserName, Password, Submit } = Login;
|
||||
const { Tab, TenantCode, UserName, Password, Submit } = Login;
|
||||
|
||||
@connect(({ login, loading }) => ({
|
||||
login,
|
||||
@ -80,6 +80,16 @@ class LoginPage extends Component {
|
||||
login.type === 'account' &&
|
||||
!submitting &&
|
||||
this.renderMessage(formatMessage({ id: 'app.login.message-invalid-credentials' }))}
|
||||
<TenantCode
|
||||
name="tenantCode"
|
||||
placeholder={`${formatMessage({ id: 'app.login.tenantCode' })}: 000000`}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: formatMessage({ id: 'validation.tenantCode.required' }),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<UserName
|
||||
name="account"
|
||||
placeholder={`${formatMessage({ id: 'app.login.userName' })}: admin`}
|
||||
|
@ -26,12 +26,17 @@ class Dept extends PureComponent {
|
||||
|
||||
return (
|
||||
<Row gutter={{ md: 8, lg: 24, xl: 48 }}>
|
||||
<Col md={8} sm={24}>
|
||||
<Col md={6} sm={24}>
|
||||
<FormItem label="部门名称">
|
||||
{getFieldDecorator('deptName')(<Input placeholder="请输入部门名称" />)}
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col md={8} sm={24}>
|
||||
<Col md={6} sm={24}>
|
||||
<FormItem label="租户编号">
|
||||
{getFieldDecorator('tenantCode')(<Input placeholder="请输入角色名称" />)}
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col md={6} sm={24}>
|
||||
<FormItem label="部门全称">
|
||||
{getFieldDecorator('fullName')(<Input placeholder="请输入部门全称" />)}
|
||||
</FormItem>
|
||||
@ -64,6 +69,10 @@ class Dept extends PureComponent {
|
||||
title: '部门名称',
|
||||
dataIndex: 'deptName',
|
||||
},
|
||||
{
|
||||
title: '租户编号',
|
||||
dataIndex: 'tenantCode',
|
||||
},
|
||||
{
|
||||
title: '部门全称',
|
||||
dataIndex: 'fullName',
|
||||
|
@ -109,12 +109,6 @@ class DeptAdd extends PureComponent {
|
||||
<Col span={10}>
|
||||
<FormItem {...formItemLayout} label="上级部门">
|
||||
{getFieldDecorator('parentId', {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择上级部门',
|
||||
},
|
||||
],
|
||||
initialValue: detail.id,
|
||||
})(
|
||||
<TreeSelect
|
||||
|
@ -121,12 +121,6 @@ class DeptEdit extends PureComponent {
|
||||
<Col span={10}>
|
||||
<FormItem {...formItemLayout} label="上级部门">
|
||||
{getFieldDecorator('parentId', {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择上级部门',
|
||||
},
|
||||
],
|
||||
initialValue: detail.parentId,
|
||||
})(
|
||||
<TreeSelect
|
||||
|
@ -117,12 +117,17 @@ class Role extends PureComponent {
|
||||
|
||||
return (
|
||||
<Row gutter={{ md: 8, lg: 24, xl: 48 }}>
|
||||
<Col md={8} sm={24}>
|
||||
<Col md={6} sm={24}>
|
||||
<FormItem label="角色名称">
|
||||
{getFieldDecorator('roleName')(<Input placeholder="请输入角色名称" />)}
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col md={8} sm={24}>
|
||||
<Col md={6} sm={24}>
|
||||
<FormItem label="租户编号">
|
||||
{getFieldDecorator('tenantCode')(<Input placeholder="请输入角色名称" />)}
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col md={6} sm={24}>
|
||||
<FormItem label="角色别名">
|
||||
{getFieldDecorator('roleAlias')(<Input placeholder="请输入角色别名" />)}
|
||||
</FormItem>
|
||||
@ -175,6 +180,10 @@ class Role extends PureComponent {
|
||||
title: '角色名称',
|
||||
dataIndex: 'roleName',
|
||||
},
|
||||
{
|
||||
title: '租户编号',
|
||||
dataIndex: 'tenantCode',
|
||||
},
|
||||
{
|
||||
title: '角色别名',
|
||||
dataIndex: 'roleAlias',
|
||||
|
105
src/pages/System/Tenant/Tenant.js
Normal file
105
src/pages/System/Tenant/Tenant.js
Normal file
@ -0,0 +1,105 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { connect } from 'dva';
|
||||
import { Button, Col, Form, Input, Row } from 'antd';
|
||||
import Panel from '../../../components/Panel';
|
||||
import { TENANT_LIST } from '../../../actions/tenant';
|
||||
import Grid from '../../../components/Sword/Grid';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
@connect(({ tenant, loading }) => ({
|
||||
tenant,
|
||||
loading: loading.models.tenant,
|
||||
}))
|
||||
@Form.create()
|
||||
class Tenant extends PureComponent {
|
||||
// ============ 查询 ===============
|
||||
handleSearch = params => {
|
||||
const { dispatch } = this.props;
|
||||
dispatch(TENANT_LIST(params));
|
||||
};
|
||||
|
||||
// ============ 查询表单 ===============
|
||||
renderSearchForm = onReset => {
|
||||
const { form } = this.props;
|
||||
const { getFieldDecorator } = form;
|
||||
|
||||
return (
|
||||
<Row gutter={{ md: 8, lg: 24, xl: 48 }}>
|
||||
<Col md={6} sm={24}>
|
||||
<FormItem label="租户编号">
|
||||
{getFieldDecorator('tenantCode')(<Input placeholder="请输入租户编号" />)}
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col md={6} sm={24}>
|
||||
<FormItem label="租户名称">
|
||||
{getFieldDecorator('tenantName')(<Input placeholder="请输入租户名称" />)}
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col md={6} sm={24}>
|
||||
<FormItem label="联系电话">
|
||||
{getFieldDecorator('contactNumber')(<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>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const code = 'tenant';
|
||||
|
||||
const {
|
||||
form,
|
||||
loading,
|
||||
tenant: { data },
|
||||
} = this.props;
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '租户编号',
|
||||
dataIndex: 'tenantCode',
|
||||
},
|
||||
{
|
||||
title: '租户名称',
|
||||
dataIndex: 'tenantName',
|
||||
},
|
||||
{
|
||||
title: '联系人',
|
||||
dataIndex: 'linkman',
|
||||
},
|
||||
{
|
||||
title: '联系电话',
|
||||
dataIndex: 'contactNumber',
|
||||
},
|
||||
{
|
||||
title: '联系地址',
|
||||
dataIndex: 'address',
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Panel>
|
||||
<Grid
|
||||
code={code}
|
||||
form={form}
|
||||
onSearch={this.handleSearch}
|
||||
renderSearchForm={this.renderSearchForm}
|
||||
loading={loading}
|
||||
data={data}
|
||||
columns={columns}
|
||||
/>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
}
|
||||
export default Tenant;
|
96
src/pages/System/Tenant/TenantAdd.js
Normal file
96
src/pages/System/Tenant/TenantAdd.js
Normal file
@ -0,0 +1,96 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { Form, Input, Card, Button } from 'antd';
|
||||
import { connect } from 'dva';
|
||||
import Panel from '../../../components/Panel';
|
||||
import styles from '../../../layouts/Sword.less';
|
||||
import { TENANT_SUBMIT } from '../../../actions/tenant';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const { TextArea } = Input;
|
||||
|
||||
@connect(({ loading }) => ({
|
||||
submitting: loading.effects['tenant/submit'],
|
||||
}))
|
||||
@Form.create()
|
||||
class TenantAdd extends PureComponent {
|
||||
handleSubmit = e => {
|
||||
e.preventDefault();
|
||||
const { dispatch, form } = this.props;
|
||||
form.validateFieldsAndScroll((err, values) => {
|
||||
if (!err) {
|
||||
dispatch(TENANT_SUBMIT(values));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
form: { getFieldDecorator },
|
||||
submitting,
|
||||
} = this.props;
|
||||
|
||||
const formItemLayout = {
|
||||
labelCol: {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 7 },
|
||||
},
|
||||
wrapperCol: {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 12 },
|
||||
md: { span: 10 },
|
||||
},
|
||||
};
|
||||
|
||||
const action = (
|
||||
<Button type="primary" onClick={this.handleSubmit} loading={submitting}>
|
||||
提交
|
||||
</Button>
|
||||
);
|
||||
|
||||
return (
|
||||
<Panel title="新增" back="/system/tenant" action={action}>
|
||||
<Form hideRequiredMark style={{ marginTop: 8 }}>
|
||||
<Card className={styles.card} bordered={false}>
|
||||
<FormItem {...formItemLayout} label="租户名称">
|
||||
{getFieldDecorator('tenantName', {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入租户名称',
|
||||
},
|
||||
],
|
||||
})(<Input placeholder="请输入租户名称" />)}
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="联系人">
|
||||
{getFieldDecorator('linkman', {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入联系人',
|
||||
},
|
||||
],
|
||||
})(<Input placeholder="请输入联系人" />)}
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="联系电话">
|
||||
{getFieldDecorator('contactNumber', {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入联系电话',
|
||||
},
|
||||
],
|
||||
})(<Input placeholder="请输入联系电话" />)}
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="联系地址">
|
||||
{getFieldDecorator('address')(
|
||||
<TextArea style={{ minHeight: 32 }} rows={3} placeholder="请输入联系地址" />
|
||||
)}
|
||||
</FormItem>
|
||||
</Card>
|
||||
</Form>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default TenantAdd;
|
122
src/pages/System/Tenant/TenantEdit.js
Normal file
122
src/pages/System/Tenant/TenantEdit.js
Normal file
@ -0,0 +1,122 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { Form, Input, Card, Button } from 'antd';
|
||||
import { connect } from 'dva';
|
||||
import Panel from '../../../components/Panel';
|
||||
import styles from '../../../layouts/Sword.less';
|
||||
import { TENANT_DETAIL, TENANT_SUBMIT } from '../../../actions/tenant';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const { TextArea } = Input;
|
||||
|
||||
@connect(({ tenant, loading }) => ({
|
||||
tenant,
|
||||
submitting: loading.effects['tenant/submit'],
|
||||
}))
|
||||
@Form.create()
|
||||
class TenantEdit extends PureComponent {
|
||||
componentWillMount() {
|
||||
const {
|
||||
dispatch,
|
||||
match: {
|
||||
params: { id },
|
||||
},
|
||||
} = this.props;
|
||||
dispatch(TENANT_DETAIL(id));
|
||||
}
|
||||
|
||||
handleSubmit = e => {
|
||||
e.preventDefault();
|
||||
const {
|
||||
dispatch,
|
||||
match: {
|
||||
params: { id },
|
||||
},
|
||||
form,
|
||||
} = this.props;
|
||||
form.validateFieldsAndScroll((err, values) => {
|
||||
if (!err) {
|
||||
const params = {
|
||||
id,
|
||||
...values,
|
||||
};
|
||||
console.log(params);
|
||||
dispatch(TENANT_SUBMIT(params));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
form: { getFieldDecorator },
|
||||
tenant: { detail },
|
||||
submitting,
|
||||
} = this.props;
|
||||
|
||||
const formItemLayout = {
|
||||
labelCol: {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 7 },
|
||||
},
|
||||
wrapperCol: {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 12 },
|
||||
md: { span: 10 },
|
||||
},
|
||||
};
|
||||
|
||||
const action = (
|
||||
<Button type="primary" onClick={this.handleSubmit} loading={submitting}>
|
||||
提交
|
||||
</Button>
|
||||
);
|
||||
|
||||
return (
|
||||
<Panel title="修改" back="/system/tenant" action={action}>
|
||||
<Form hideRequiredMark style={{ marginTop: 8 }}>
|
||||
<Card className={styles.card} bordered={false}>
|
||||
<FormItem {...formItemLayout} label="租户名称">
|
||||
{getFieldDecorator('tenantName', {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入租户名称',
|
||||
},
|
||||
],
|
||||
initialValue: detail.tenantName,
|
||||
})(<Input placeholder="请输入租户名称" />)}
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="联系人">
|
||||
{getFieldDecorator('linkman', {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入联系人',
|
||||
},
|
||||
],
|
||||
initialValue: detail.linkman,
|
||||
})(<Input placeholder="请输入联系人" />)}
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="联系电话">
|
||||
{getFieldDecorator('contactNumber', {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入联系电话',
|
||||
},
|
||||
],
|
||||
initialValue: detail.contactNumber,
|
||||
})(<Input placeholder="请输入联系电话" />)}
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="联系地址">
|
||||
{getFieldDecorator('address', {
|
||||
initialValue: detail.address,
|
||||
})(<TextArea style={{ minHeight: 32 }} rows={3} placeholder="请输入联系地址" />)}
|
||||
</FormItem>
|
||||
</Card>
|
||||
</Form>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default TenantEdit;
|
83
src/pages/System/Tenant/TenantView.js
Normal file
83
src/pages/System/Tenant/TenantView.js
Normal file
@ -0,0 +1,83 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import router from 'umi/router';
|
||||
import { Form, Card, Button } from 'antd';
|
||||
import { connect } from 'dva';
|
||||
import Panel from '../../../components/Panel';
|
||||
import styles from '../../../layouts/Sword.less';
|
||||
import { TENANT_DETAIL } from '../../../actions/tenant';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
@connect(({ tenant }) => ({
|
||||
tenant,
|
||||
}))
|
||||
@Form.create()
|
||||
class TenantView extends PureComponent {
|
||||
componentWillMount() {
|
||||
const {
|
||||
dispatch,
|
||||
match: {
|
||||
params: { id },
|
||||
},
|
||||
} = this.props;
|
||||
dispatch(TENANT_DETAIL(id));
|
||||
}
|
||||
|
||||
handleEdit = () => {
|
||||
const {
|
||||
match: {
|
||||
params: { id },
|
||||
},
|
||||
} = this.props;
|
||||
router.push(`/system/tenant/edit/${id}`);
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
tenant: { detail },
|
||||
} = this.props;
|
||||
|
||||
const formItemLayout = {
|
||||
labelCol: {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 7 },
|
||||
},
|
||||
wrapperCol: {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 12 },
|
||||
md: { span: 10 },
|
||||
},
|
||||
};
|
||||
|
||||
const action = (
|
||||
<Button type="primary" onClick={this.handleEdit}>
|
||||
修改
|
||||
</Button>
|
||||
);
|
||||
|
||||
return (
|
||||
<Panel title="查看" back="/system/tenant" action={action}>
|
||||
<Form hideRequiredMark style={{ marginTop: 8 }}>
|
||||
<Card className={styles.card} bordered={false}>
|
||||
<FormItem {...formItemLayout} label="租户编号">
|
||||
<span>{detail.tenantCode}</span>
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="租户名称">
|
||||
<span>{detail.tenantName}</span>
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="联系人">
|
||||
<span>{detail.linkman}</span>
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="联系电话">
|
||||
<span>{detail.contactNumber}</span>
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="联系地址">
|
||||
<span>{detail.address}</span>
|
||||
</FormItem>
|
||||
</Card>
|
||||
</Form>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
}
|
||||
export default TenantView;
|
@ -173,6 +173,10 @@ class User extends PureComponent {
|
||||
} = this.props;
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '租户编号',
|
||||
dataIndex: 'tenantCode',
|
||||
},
|
||||
{
|
||||
title: '登录账号',
|
||||
dataIndex: 'account',
|
||||
|
@ -4,7 +4,7 @@ import { connect } from 'dva';
|
||||
import moment from 'moment';
|
||||
import Panel from '../../../components/Panel';
|
||||
import styles from '../../../layouts/Sword.less';
|
||||
import { USER_INIT, USER_SUBMIT } from '../../../actions/user';
|
||||
import { USER_INIT, USER_CHANGE_INIT, USER_SUBMIT } from '../../../actions/user';
|
||||
import func from '../../../utils/Func';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
@ -42,11 +42,17 @@ class UserAdd extends PureComponent {
|
||||
});
|
||||
};
|
||||
|
||||
handleChange = value => {
|
||||
const { dispatch, form } = this.props;
|
||||
form.resetFields(['roleId', 'deptId']);
|
||||
dispatch(USER_CHANGE_INIT({ tenantCode: value }));
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
form: { getFieldDecorator },
|
||||
user: {
|
||||
init: { roleTree, deptTree },
|
||||
init: { roleTree, deptTree, tenantList },
|
||||
},
|
||||
submitting,
|
||||
} = this.props;
|
||||
@ -60,15 +66,6 @@ class UserAdd extends PureComponent {
|
||||
},
|
||||
};
|
||||
|
||||
const formAllItemLayout = {
|
||||
labelCol: {
|
||||
span: 4,
|
||||
},
|
||||
wrapperCol: {
|
||||
span: 20,
|
||||
},
|
||||
};
|
||||
|
||||
const action = (
|
||||
<Button type="primary" onClick={this.handleSubmit} loading={submitting}>
|
||||
提交
|
||||
@ -80,8 +77,8 @@ class UserAdd extends PureComponent {
|
||||
<Form hideRequiredMark style={{ marginTop: 8 }}>
|
||||
<Card title="基本信息" className={styles.card} bordered={false}>
|
||||
<Row gutter={24}>
|
||||
<Col span={20}>
|
||||
<FormItem {...formAllItemLayout} label="登录账号">
|
||||
<Col span={10}>
|
||||
<FormItem {...formItemLayout} label="登录账号">
|
||||
{getFieldDecorator('account', {
|
||||
rules: [
|
||||
{
|
||||
@ -92,6 +89,34 @@ class UserAdd extends PureComponent {
|
||||
})(<Input placeholder="请输入登录账号" />)}
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span={10}>
|
||||
<FormItem {...formItemLayout} label="所属租户">
|
||||
{getFieldDecorator('tenantCode', {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择所属租户',
|
||||
},
|
||||
],
|
||||
})(
|
||||
<Select
|
||||
showSearch
|
||||
onChange={this.handleChange}
|
||||
filterOption={(input, option) =>
|
||||
option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}
|
||||
allowClear
|
||||
placeholder="请选择所属租户"
|
||||
>
|
||||
{tenantList.map(d => (
|
||||
<Select.Option key={d.tenantCode} value={d.tenantCode}>
|
||||
{d.tenantName}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
)}
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row gutter={24}>
|
||||
<Col span={10}>
|
||||
|
@ -5,7 +5,7 @@ import { connect } from 'dva';
|
||||
import Panel from '../../../components/Panel';
|
||||
import func from '../../../utils/Func';
|
||||
import styles from '../../../layouts/Sword.less';
|
||||
import { USER_DETAIL, USER_INIT, USER_SUBMIT } from '../../../actions/user';
|
||||
import { USER_CHANGE_INIT, USER_DETAIL, USER_INIT, USER_SUBMIT } from '../../../actions/user';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
@ -49,12 +49,18 @@ class UserEdit extends PureComponent {
|
||||
});
|
||||
};
|
||||
|
||||
handleChange = value => {
|
||||
const { dispatch, form } = this.props;
|
||||
form.resetFields(['roleId', 'deptId']);
|
||||
dispatch(USER_CHANGE_INIT({ tenantCode: value }));
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
form: { getFieldDecorator },
|
||||
user: {
|
||||
detail,
|
||||
init: { roleTree, deptTree },
|
||||
init: { roleTree, deptTree, tenantList },
|
||||
},
|
||||
submitting,
|
||||
} = this.props;
|
||||
@ -70,15 +76,6 @@ class UserEdit extends PureComponent {
|
||||
},
|
||||
};
|
||||
|
||||
const formAllItemLayout = {
|
||||
labelCol: {
|
||||
span: 4,
|
||||
},
|
||||
wrapperCol: {
|
||||
span: 20,
|
||||
},
|
||||
};
|
||||
|
||||
const action = (
|
||||
<Button type="primary" onClick={this.handleSubmit} loading={submitting}>
|
||||
提交
|
||||
@ -90,8 +87,8 @@ class UserEdit extends PureComponent {
|
||||
<Form hideRequiredMark style={{ marginTop: 8 }}>
|
||||
<Card title="基本信息" className={styles.card} bordered={false}>
|
||||
<Row gutter={24}>
|
||||
<Col span={20}>
|
||||
<FormItem {...formAllItemLayout} label="登录账号">
|
||||
<Col span={10}>
|
||||
<FormItem {...formItemLayout} label="登录账号">
|
||||
{getFieldDecorator('account', {
|
||||
rules: [
|
||||
{
|
||||
@ -103,6 +100,35 @@ class UserEdit extends PureComponent {
|
||||
})(<Input placeholder="请输入登录账号" />)}
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span={10}>
|
||||
<FormItem {...formItemLayout} label="所属租户">
|
||||
{getFieldDecorator('tenantCode', {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择所属租户',
|
||||
},
|
||||
],
|
||||
initialValue: detail.tenantCode,
|
||||
})(
|
||||
<Select
|
||||
showSearch
|
||||
onChange={this.handleChange}
|
||||
filterOption={(input, option) =>
|
||||
option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}
|
||||
allowClear
|
||||
placeholder="请选择所属租户"
|
||||
>
|
||||
{tenantList.map(d => (
|
||||
<Select.Option key={d.tenantCode} value={d.tenantCode}>
|
||||
{d.tenantName}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
)}
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row gutter={24}>
|
||||
<Col span={10}>
|
||||
|
@ -46,15 +46,6 @@ class UserView extends PureComponent {
|
||||
},
|
||||
};
|
||||
|
||||
const formAllItemLayout = {
|
||||
labelCol: {
|
||||
span: 4,
|
||||
},
|
||||
wrapperCol: {
|
||||
span: 20,
|
||||
},
|
||||
};
|
||||
|
||||
const action = (
|
||||
<Button type="primary" onClick={this.handleEdit}>
|
||||
修改
|
||||
@ -66,11 +57,16 @@ class UserView extends PureComponent {
|
||||
<Form hideRequiredMark style={{ marginTop: 8 }}>
|
||||
<Card title="基本信息" className={styles.card} bordered={false}>
|
||||
<Row gutter={24}>
|
||||
<Col span={20}>
|
||||
<FormItem {...formAllItemLayout} label="登录账号">
|
||||
<Col span={10}>
|
||||
<FormItem {...formItemLayout} label="登录账号">
|
||||
<span>{detail.account}</span>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span={10}>
|
||||
<FormItem {...formItemLayout} label="所属租户">
|
||||
<span>{detail.tenantCode}</span>
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row gutter={24}>
|
||||
<Col span={10}>
|
||||
|
29
src/services/tenant.js
Normal file
29
src/services/tenant.js
Normal file
@ -0,0 +1,29 @@
|
||||
import { stringify } from 'qs';
|
||||
import func from '../utils/Func';
|
||||
import request from '../utils/request';
|
||||
|
||||
export async function list(params) {
|
||||
return request(`/api/blade-system/tenant/list?${stringify(params)}`);
|
||||
}
|
||||
|
||||
export async function select(params) {
|
||||
return request(`/api/blade-system/tenant/select?${stringify(params)}`);
|
||||
}
|
||||
|
||||
export async function submit(params) {
|
||||
return request('/api/blade-system/tenant/submit', {
|
||||
method: 'POST',
|
||||
body: params,
|
||||
});
|
||||
}
|
||||
|
||||
export async function detail(params) {
|
||||
return request(`/api/blade-system/tenant/detail?${stringify(params)}`);
|
||||
}
|
||||
|
||||
export async function remove(params) {
|
||||
return request('/api/blade-system/tenant/remove', {
|
||||
method: 'POST',
|
||||
body: func.toFormData(params),
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue
Block a user