diff --git a/README.md b/README.md index 90119f2..b7a5cd7 100644 --- a/README.md +++ b/README.md @@ -1,70 +1,119 @@ -## 简介 -* Sword 是 [SpringBlade](https://gitee.com/smallc/SpringBlade)前端UI项目,基于react 、ant design、dva,用于快速构建系统中后台业务。 -* Sword 已入选 ant design 官方脚手架市场,地址:[scaffolds.ant.design](http://scaffold.ant.design/#/scaffolds/Sword) +

+ Downloads + Build Status + Build Status + Coverage Status + Downloads + + Downloads + + + Downloads + +

-## 文档 -* 文档地址:[Sword开发手册](https://www.kancloud.cn/smallchill/sword) +## SpringBlade微服务开发平台 +* 采用前后端分离的模式,前端开源两个框架:[Sword](https://gitee.com/smallc/Sword) (基于 React、Ant Design)、[Saber](https://gitee.com/smallc/Saber) (基于 Vue、Element-UI) +* 后端采用SpringCloud全家桶,并同时对其基础组件做了高度的封装,单独开源出一个框架:[BladeTool](https://github.com/chillzhuang/blade-tool) +* [BladeTool](https://github.com/chillzhuang/blade-tool)已推送至Maven中央库,直接引入即可,减少了工程的臃肿,也可更注重于业务开发 +* 集成Sentinel从流量控制、熔断降级、系统负载等多个维度保护服务的稳定性。 +* 注册中心、配置中心选型Nacos,为工程瘦身的同时加强各模块之间的联动。 +* 使用Traefik进行反向代理,监听后台变化自动化应用新的配置文件。 +* 极简封装了多租户底层,用更少的代码换来拓展性更强的SaaS多租户系统。 +* 借鉴OAuth2,实现了多终端认证系统,可控制子系统的token权限互相隔离。 +* 借鉴Security,封装了Secure模块,采用JWT做Token认证,可拓展集成Redis等细颗粒度控制方案。 +* 稳定生产了一年,经历了从Camden -> Greenwich的技术架构,也经历了从fat jar -> docker -> k8s + jenkins的部署架构 +* 项目分包明确,规范微服务的开发模式,使包与包之间的分工清晰。 + +## 架构图 + + +## 工程结构 +``` +SpringBlade +├── blade-auth -- 授权服务提供 +├── blade-common -- 常用工具封装包 +├── blade-gateway -- Spring Cloud 网关 +├── blade-ops -- 运维中心 +├ ├── blade-admin -- spring-cloud后台管理 +├ ├── blade-develop -- 代码生成 +├ ├── blade-resource -- 资源管理 +├ ├── blade-seata-order -- seata分布式事务demo +├ ├── blade-seata-storage -- seata分布式事务demo +├── blade-service -- 业务模块 +├ ├── blade-desk -- 工作台模块 +├ ├── blade-log -- 日志模块 +├ ├── blade-system -- 系统模块 +├ └── blade-user -- 用户模块 +├── blade-service-api -- 业务模块api封装 +├ ├── blade-desk-api -- 工作台api +├ ├── blade-dict-api -- 字典api +├ ├── blade-system-api -- 系统api +└── └── blade-user-api -- 用户api +``` ## 官网 * 官网地址:[https://bladex.vip](https://bladex.vip) +* 问答社区:[https://sns.bladex.vip](https://sns.bladex.vip) +* 会员计划:[SpringBlade会员计划](https://gitee.com/smallc/SpringBlade/wikis/SpringBlade会员计划) +* 交流一群:`477853168` +* 交流二群:`751253339` ## 在线演示 -* Sword演示地址:[https://sword.bladex.vip](https://sword.bladex.vip) -* Saber演示地址:[https://saber.bladex.vip](https://saber.bladex.vip) +* Saber-基于Vue:[https://saber.bladex.vip](https://saber.bladex.vip) +* Sword-基于React:[https://sword.bladex.vip](https://sword.bladex.vip) +* Archer-全能代码生成系统:[https://archer.bladex.vip](https://archer.bladex.vip) -## 后端项目地址 -* [Gitee地址](https://gitee.com/smallc/SpringBlade) -* [Github地址](https://github.com/chillzhuang/SpringBlade) - -## 前端项目地址 -* [Sword--基于React](https://gitee.com/smallc/Sword) -* [Saber--基于Vue](https://gitee.com/smallc/Saber) - -## 特性 - -- :gem: **优雅美观**:基于 Ant Design 体系精心设计 -- :triangular_ruler: **常见设计模式**:提炼自中后台应用的典型页面和场景 -- :rocket: **最新技术栈**:使用 React/umi/dva/antd 等前端前沿技术开发 -- :iphone: **响应式**:针对不同屏幕大小设计 -- :art: **主题**:可配置的主题满足多样化的品牌诉求 -- :globe_with_meridians: **国际化**:内建业界通用的国际化方案 -- :zap: **最佳实践**:良好的工程实践助您持续产出高质量代码 -- :1234: **Mock 数据**:实用的本地数据调试方案 -- :white_check_mark: **UI 测试**:自动化测试保障前端产品质量 - -## 支持环境 - -现代浏览器及 IE11。 - -| [IE / Edge](http://godban.github.io/browsers-support-badges/)
IE / Edge | [Firefox](http://godban.github.io/browsers-support-badges/)
Firefox | [Chrome](http://godban.github.io/browsers-support-badges/)
Chrome | [Safari](http://godban.github.io/browsers-support-badges/)
Safari | [Opera](http://godban.github.io/browsers-support-badges/)
Opera | -| --------- | --------- | --------- | --------- | --------- | -| IE11, Edge| last 2 versions| last 2 versions| last 2 versions| last 2 versions +## 技术文档 +* [开发手册一览](https://gitee.com/smallc/SpringBlade/wikis/SpringBlade开发手册) +* [常见问题集锦](https://sns.bladex.vip/article-14966.html) +## 项目地址 +* 后端Gitee地址:[https://gitee.com/smallc/SpringBlade](https://gitee.com/smallc/SpringBlade) +* 后端Github地址:[https://github.com/chillzhuang/SpringBlade](https://github.com/chillzhuang/SpringBlade) +* 后端SpringBoot版:[https://gitee.com/smallc/SpringBlade/tree/2.0-boot/](https://gitee.com/smallc/SpringBlade/tree/2.0-boot/) +* 前端框架Sword(基于React):[https://gitee.com/smallc/Sword](https://gitee.com/smallc/Sword) +* 前端框架Saber(基于Vue):[https://gitee.com/smallc/Saber](https://gitee.com/smallc/Saber) +* 核心框架项目地址:[https://github.com/chillzhuang/blade-tool](https://github.com/chillzhuang/blade-tool) ## 用户权益 * 允许免费用于学习、毕设、公司项目、私活等。 * 代码文件需保留相关license信息。 - -## 禁止事项 -* 直接将本项目挂淘宝等商业平台出售。 -* 业务代码50%以上相似度的二次开源,二次开源需先联系作者。 - -注意:若禁止条款被发现有权追讨19999的授权费。 +* 禁止直接将本项目挂淘宝等商业平台出售。 +* 非界面代码50%以上相似度的二次开源,二次开源需先联系作者。 ## 如何启动 ``` $ git clone https://gitee.com/smallc/Sword.git $ cd Sword -$ npm install +$ yarn install 或者 npm install # mock模式 -$ npm start +$ yarn start 或者 npm start # 服务模式 -$ npm run start:no-mock -# 访问 http://localhost:88 +$ yarn run start:no-mock 或者 npm run start:no-mock +# 访问 http://localhost:8888 +# 推荐使用yarn ``` # 界面 -## Sword界面一览 + +## [BladeX](https://bladex.vip/#/vip) 工作流一览 + + + + + + + + + + + + + +
+ +## [Sword](https://gitee.com/smallc/Sword) 界面一览 @@ -88,6 +137,22 @@ $ npm run start:no-mock
+## [Saber](https://gitee.com/smallc/Saber) 界面一览 + + + + + + + + + + + + + +
+ ## 监控界面一览 @@ -116,18 +181,5 @@ $ npm run start:no-mock
-## Saber界面一览 - - - - - - - - - - - - - -
+## 关注我们 +![](https://images.gitee.com/uploads/images/2019/0330/065148_f0ada806_410595.jpeg) diff --git a/config/router.config.js b/config/router.config.js index 2180332..e8d1306 100644 --- a/config/router.config.js +++ b/config/router.config.js @@ -52,18 +52,19 @@ export default [ }, { path: '/account/settings', - component: './Account/Settings/Info', + //component: './Account/Settings/Info', routes: [ { path: '/account/settings', redirect: '/account/settings/base' }, { path: '/account/settings/base', component: './Account/Settings/BaseView' }, - { path: '/account/settings/security', component: './Account/Settings/SecurityView' }, - { path: '/account/settings/binding', component: './Account/Settings/BindingView' }, + { path: '/account/settings/password', component: './Account/Settings/PasswordView' }, + //{ path: '/account/settings/security', component: './Account/Settings/SecurityView' }, + //{ path: '/account/settings/binding', component: './Account/Settings/BindingView' }, { path: '/account/settings/notification', component: './Account/Settings/NotificationView', }, ], - }, + } ], }, { @@ -226,6 +227,23 @@ export default [ { path: '/tool/code/view/:id', component: './System/Code/CodeView' }, ], }, + { + path: '/tool/datasource', + routes: [ + { path: '/tool/datasource', redirect: '/tool/datasource/list' }, + { path: '/tool/datasource/list', component: './System/DataSource/DataSource' }, + { path: '/tool/datasource/add', component: './System/DataSource/DataSourceAdd' }, + { path: '/tool/datasource/add/:id', component: './System/DataSource/DataSourceAdd' }, + { + path: '/tool/datasource/edit/:id', + component: './System/DataSource/DataSourceEdit', + }, + { + path: '/tool/datasource/view/:id', + component: './System/DataSource/DataSourceView', + }, + ], + }, ], }, { diff --git a/mock/dept.js b/mock/dept.js index 64d1755..b8370b2 100644 --- a/mock/dept.js +++ b/mock/dept.js @@ -6,21 +6,21 @@ function getFakeList(req, res) { data.push({ id: '1', deptName: '刀锋科技', - tenantCode: '000000', + tenantId: '000000', fullName: '江苏刀锋科技有限公司', sort: '1', children: [ { id: '2', deptName: '常州刀锋', - tenantCode: '000000', + tenantId: '000000', fullName: '常州刀锋科技有限公司', sort: '1', }, { id: '3', deptName: '南京刀锋', - tenantCode: '000000', + tenantId: '000000', fullName: '南京刀锋科技有限公司', sort: '2', }, @@ -36,7 +36,7 @@ function getFakeDetail(req, res) { id: 2, parentId: 1, parentName: '江苏刀锋', - tenantCode: '000000', + tenantId: '000000', deptName: '常州刀锋', fullName: '常州刀锋科技有限公司', sort: 1, diff --git a/mock/role.js b/mock/role.js index 0cdb98b..01a1244 100644 --- a/mock/role.js +++ b/mock/role.js @@ -7,14 +7,14 @@ function getFakeList(req, res) { { id: '1', roleName: '超级管理员', - tenantCode: '000000', + tenantId: '000000', roleAlias: 'administrator', sort: '1', children: [ { id: '2', roleName: '管理员', - tenantCode: '000001', + tenantId: '000001', roleAlias: 'admin', sort: '1', }, @@ -23,21 +23,21 @@ function getFakeList(req, res) { { id: '3', roleName: '用户', - tenantCode: '000002', + tenantId: '000002', roleAlias: 'user', sort: '2', children: [ { id: '4', roleName: '普通用户', - tenantCode: '000003', + tenantId: '000003', roleAlias: 'user', sort: '1', }, { id: '5', roleName: '访客', - tenantCode: '000004', + tenantId: '000004', roleAlias: 'guest', sort: '2', }, @@ -54,7 +54,7 @@ function getFakeDetail(req, res) { id: 2, parentId: 1, parentName: '超级管理员', - tenantCode: '000000', + tenantId: '000000', roleName: '用户', roleAlias: 'user', sort: 1, diff --git a/mock/tenant.js b/mock/tenant.js index ce4da02..06e43f3 100644 --- a/mock/tenant.js +++ b/mock/tenant.js @@ -6,7 +6,7 @@ function getFakeList(req, res) { list.push( { id: '1', - tenantCode: '000000', + tenantId: '000000', tenantName: '管理组', linkman: 'Chill', contactNumber: '66666666666', @@ -14,7 +14,7 @@ function getFakeList(req, res) { }, { id: '2', - tenantCode: '000001', + tenantId: '000001', tenantName: '用户组', linkman: 'Bill', contactNumber: '23333333333', @@ -36,7 +36,7 @@ function getFakeDetail(req, res) { const json = { code: 200, success: true, msg: '操作成功' }; json.data = { id: '1', - tenantCode: '000000', + tenantId: '000000', tenantName: '管理组', linkman: 'Chill', contactNumber: '66666666666', @@ -54,11 +54,11 @@ function getFakeTenantSelect(req, res) { const json = { code: 200, success: true, msg: '操作成功' }; json.data = [ { - tenantCode: '000000', + tenantId: '000000', tenantName: '管理组', }, { - tenantCode: '000001', + tenantId: '000001', tenantName: '用户组', }, ]; diff --git a/mock/user.js b/mock/user.js index caf7ebe..a738e5a 100644 --- a/mock/user.js +++ b/mock/user.js @@ -6,7 +6,7 @@ function getFakeList(req, res) { list.push( { id: '1', - tenantCode: '000000', + tenantId: '000000', account: 'admin', name: '超级管理员', realName: '管理员', @@ -18,7 +18,7 @@ function getFakeList(req, res) { }, { id: '2', - tenantCode: '000001', + tenantId: '000001', account: 'user', name: '系统用户', realName: '用户', @@ -44,7 +44,7 @@ function getFakeDetail(req, res) { const json = { code: 200, success: true, msg: '操作成功' }; json.data = { id: '1', - tenantCode: '000000', + tenantId: '000000', account: 'admin', name: '超级管理员', realName: '管理员', @@ -74,6 +74,7 @@ const proxy = { 'POST /api/blade-user/grant': fakeSuccess, 'POST /api/blade-user/reset-password': fakeSuccess, 'POST /api/blade-user/submit': fakeSuccess, + 'POST /api/blade-user/update': fakeSuccess, 'POST /api/blade-user/remove': fakeSuccess, // 支持值为 Object 和 Array diff --git a/package.json b/package.json index 62fbe4f..b3e515e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sword", - "version": "1.0.0", + "version": "2.5.4", "description": "An out-of-box UI solution for enterprise applications", "private": true, "scripts": { diff --git a/src/actions/code.js b/src/actions/code.js index 27a3508..a4f5998 100644 --- a/src/actions/code.js +++ b/src/actions/code.js @@ -7,6 +7,13 @@ export function CODE_LIST(payload) { }; } +export function CODE_INIT() { + return { + type: `${CODE_NAMESPACE}/fetchInit`, + payload: { code: 'yes_no' }, + }; +} + export function CODE_DETAIL(id) { return { type: `${CODE_NAMESPACE}/fetchDetail`, diff --git a/src/actions/datasource.js b/src/actions/datasource.js new file mode 100644 index 0000000..45ba363 --- /dev/null +++ b/src/actions/datasource.js @@ -0,0 +1,36 @@ +export const DATASOURCE_NAMESPACE = 'datasource'; + +export function DATASOURCE_LIST(payload) { + return { + type: `${DATASOURCE_NAMESPACE}/fetchList`, + payload, + }; +} + +export function DATASOURCE_DETAIL(id) { + return { + type: `${DATASOURCE_NAMESPACE}/fetchDetail`, + payload: { id }, + }; +} + +export function DATASOURCE_CLEAR_DETAIL() { + return { + type: `${DATASOURCE_NAMESPACE}/clearDetail`, + payload: {}, + }; +} + +export function DATASOURCE_SUBMIT(payload) { + return { + type: `${DATASOURCE_NAMESPACE}/submit`, + payload, + }; +} + +export function DATASOURCE_REMOVE(payload) { + return { + type: `${DATASOURCE_NAMESPACE}/remove`, + payload, + }; +} diff --git a/src/actions/user.js b/src/actions/user.js index 36e396f..0a1fe88 100644 --- a/src/actions/user.js +++ b/src/actions/user.js @@ -43,6 +43,13 @@ export function USER_SUBMIT(payload) { }; } +export function USER_UPDATE(payload) { + return { + type: `${USER_NAMESPACE}/update`, + payload, + }; +} + export function USER_REMOVE(payload) { return { type: `${USER_NAMESPACE}/remove`, diff --git a/src/components/GlobalHeader/RightContent.js b/src/components/GlobalHeader/RightContent.js index 497ca50..4fe012e 100644 --- a/src/components/GlobalHeader/RightContent.js +++ b/src/components/GlobalHeader/RightContent.js @@ -96,14 +96,14 @@ export default class GlobalHeaderRight extends PureComponent { selectedKeys={[]} onClick={onMenuClick} > - - - - + + + + diff --git a/src/components/Login/index.d.ts b/src/components/Login/index.d.ts index e4588fe..af06a3c 100644 --- a/src/components/Login/index.d.ts +++ b/src/components/Login/index.d.ts @@ -12,7 +12,7 @@ export interface ILoginProps { export default class Login extends React.Component { public static Tab: typeof LoginTab; - public static TenantCode: typeof LoginItem; + public static TenantId: typeof LoginItem; public static UserName: typeof LoginItem; public static Password: typeof LoginItem; public static Mobile: typeof LoginItem; diff --git a/src/components/Login/map.js b/src/components/Login/map.js index 850b79b..cd645b1 100644 --- a/src/components/Login/map.js +++ b/src/components/Login/map.js @@ -3,17 +3,17 @@ import { Icon } from 'antd'; import styles from './index.less'; export default { - TenantCode: { + TenantId: { props: { size: 'large', - id: 'tenantCode', + id: 'tenantId', prefix: , placeholder: 'admin', }, rules: [ { required: true, - message: 'Please enter tenantcode!', + message: 'Please enter tenantId!', }, ], }, diff --git a/src/components/PageHeader/index.js b/src/components/PageHeader/index.js index 5d47b34..f9813e1 100644 --- a/src/components/PageHeader/index.js +++ b/src/components/PageHeader/index.js @@ -52,10 +52,12 @@ export default class PageHeader extends PureComponent {
{logo &&
{logo}
}
-
- {title &&

{title}

} - {action &&
{action}
} -
+ {title && ( +
+

{title}

+ {action &&
{action}
} +
+ )}
{content &&
{content}
} {extraContent &&
{extraContent}
} diff --git a/src/components/Sword/Grid.js b/src/components/Sword/Grid.js index aff6b9a..0b8f796 100644 --- a/src/components/Sword/Grid.js +++ b/src/components/Sword/Grid.js @@ -34,7 +34,9 @@ export default class Grid extends PureComponent { const { form } = this.props; form.validateFields(async (err, fieldsValue) => { - if (err) return; + if (err) { + return; + } const values = { ...fieldsValue, @@ -57,7 +59,9 @@ export default class Grid extends PureComponent { formValues: {}, selectedRows: [], }); - if (onReset) onReset(); + if (onReset) { + onReset(); + } this.refreshTable(); }; @@ -79,7 +83,9 @@ export default class Grid extends PureComponent { size, ...formValues, }; - if (onSearch) onSearch(params); + if (onSearch) { + onSearch(params); + } }; handleSelectRows = rows => { @@ -105,12 +111,13 @@ export default class Grid extends PureComponent { }); }; - handelToolBarClick = btn => { + handleToolBarClick = btn => { + const { selectedRows } = this.state; const keys = this.getSelectKeys(); - this.handelClick(btn, keys); + this.handleClick(btn, keys, selectedRows); }; - handelClick = (btn, keys = []) => { + handleClick = (btn, keys = [], rows) => { const { path, alias } = btn; const { btnCallBack } = this.props; const refresh = (temp = true) => this.refreshTable(temp); @@ -176,7 +183,7 @@ export default class Grid extends PureComponent { return; } if (btnCallBack) { - btnCallBack({ btn, keys, refresh }); + btnCallBack({ btn, keys, rows, refresh }); } }; @@ -195,12 +202,13 @@ export default class Grid extends PureComponent { renderSearchForm, renderLeftButton, renderRightButton, + renderActionButton, } = this.props; let { columns } = this.props; const actionButtons = buttons.filter(button => button.action === 2 || button.action === 3); - if (columns && Array.isArray(columns) && actionButtons.length > 0) { + if (columns && Array.isArray(columns) && (actionButtons.length > 0 || renderActionButton)) { const key = pkField || rowKey || 'id'; columns = [ ...columns, @@ -209,17 +217,24 @@ export default class Grid extends PureComponent { width: actionColumnWidth || 200, render: (text, record) => ( - {actionButtons.map((button, index) => ( - - {index > 0 ? : null} - this.handelClick(button, [record[childPkField || key]])} - > - - - - ))} +
+ {actionButtons.map((button, index) => ( + + {index > 0 ? : null} + + this.handleClick(button, [record[childPkField || key]], [record]) + } + > + + + + ))} + {renderActionButton + ? renderActionButton([record[childPkField || key]], [record]) + : null} +
), }, @@ -236,7 +251,7 @@ export default class Grid extends PureComponent { buttons={buttons} renderLeftButton={renderLeftButton} renderRightButton={renderRightButton} - onClick={this.handelToolBarClick} + onClick={this.handleToolBarClick} />
diff --git a/src/layouts/Header.js b/src/layouts/Header.js index 18a09f6..69571c5 100644 --- a/src/layouts/Header.js +++ b/src/layouts/Header.js @@ -62,8 +62,11 @@ class HeaderView extends React.Component { return; } if (key === 'userinfo') { - message.success('即将开放'); - // router.push('/account/settings/base'); + router.push('/account/settings/base'); + return; + } + if (key === 'password') { + router.push('/account/settings/password'); return; } if (key === 'triggerError') { diff --git a/src/locales/en-US/login.js b/src/locales/en-US/login.js index a7bc864..ac476dc 100644 --- a/src/locales/en-US/login.js +++ b/src/locales/en-US/login.js @@ -1,5 +1,5 @@ export default { - 'app.login.tenantCode': 'tenantCode', + 'app.login.tenantId': 'tenantId', 'app.login.userName': 'userName', 'app.login.password': 'password', 'app.login.message-invalid-credentials': 'Invalid username or password(admin/ant.design)', @@ -21,7 +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.tenantId': 'Please enter your tenantId!', 'validation.userName.required': 'Please enter your userName!', 'validation.password.required': 'Please enter your password!', 'validation.password.twice': 'The passwords entered twice do not match!', diff --git a/src/locales/en-US/menu.js b/src/locales/en-US/menu.js index cc83d16..40e9282 100644 --- a/src/locales/en-US/menu.js +++ b/src/locales/en-US/menu.js @@ -24,6 +24,7 @@ export default { 'menu.monitor.doc': 'api doc', 'menu.tool': 'develop', 'menu.tool.code': 'code generate', + 'menu.tool.datasource': 'datasource', 'menu.result': 'Result', 'menu.result.success': 'Success', 'menu.result.fail': 'Fail', @@ -34,6 +35,7 @@ export default { 'menu.exception.trigger': 'Trigger', 'menu.account': 'Account', 'menu.account.center': 'Account Center', + 'menu.account.password': 'Modify Password', 'menu.account.settings': 'Account Settings', 'menu.account.trigger': 'Trigger Error', 'menu.account.logout': 'Logout', diff --git a/src/locales/en-US/settings.js b/src/locales/en-US/settings.js index 822dd00..0e8318b 100644 --- a/src/locales/en-US/settings.js +++ b/src/locales/en-US/settings.js @@ -9,6 +9,8 @@ export default { 'app.settings.basic.email-message': 'Please input your email!', 'app.settings.basic.nickname': 'Nickname', 'app.settings.basic.nickname-message': 'Please input your Nickname!', + 'app.settings.basic.realname': 'Realname', + 'app.settings.basic.realname-message': 'Please input your Realname!', 'app.settings.basic.profile': 'Personal profile', 'app.settings.basic.profile-message': 'Please input your personal profile!', 'app.settings.basic.profile-placeholder': 'Brief introduction to yourself', @@ -21,6 +23,12 @@ export default { 'app.settings.basic.phone': 'Phone Number', 'app.settings.basic.phone-message': 'Please input your phone!', 'app.settings.basic.update': 'Update Information', + 'app.settings.password.old': 'Old Password', + 'app.settings.password.old-message': 'Please input your Old Password!', + 'app.settings.password.new': 'New Password', + 'app.settings.password.new-message': 'Please input your new Password!', + 'app.settings.password.new1': 'New Password1', + 'app.settings.password.new1-message': 'Please comfirm your new Password!', 'app.settings.security.strong': 'Strong', 'app.settings.security.medium': 'Medium', 'app.settings.security.weak': 'Weak', diff --git a/src/locales/zh-CN/login.js b/src/locales/zh-CN/login.js index 67696d6..64b3887 100644 --- a/src/locales/zh-CN/login.js +++ b/src/locales/zh-CN/login.js @@ -1,5 +1,5 @@ export default { - 'app.login.tenantCode': '租户编号', + 'app.login.tenantId': '租户ID', 'app.login.userName': '用户名', 'app.login.password': '密码', 'app.login.message-invalid-credentials': '账户或密码错误(admin/ant.design)', @@ -21,7 +21,7 @@ export default { 'app.register-result.view-mailbox': '查看邮箱', 'validation.email.required': '请输入邮箱地址!', 'validation.email.wrong-format': '邮箱地址格式错误!', - 'validation.tenantCode.required': '请输入租户编号!', + 'validation.tenantId.required': '请输入租户ID!', 'validation.userName.required': '请输入用户名!', 'validation.password.required': '请输入密码!', 'validation.password.twice': '两次输入的密码不匹配!', diff --git a/src/locales/zh-CN/menu.js b/src/locales/zh-CN/menu.js index eafd4bb..f8cee1d 100644 --- a/src/locales/zh-CN/menu.js +++ b/src/locales/zh-CN/menu.js @@ -24,6 +24,7 @@ export default { 'menu.monitor.doc': '接口文档', 'menu.tool': '研发工具', 'menu.tool.code': '代码生成', + 'menu.tool.datasource': '数据源管理', 'menu.result': '结果页', 'menu.result.success': '成功页', 'menu.result.fail': '失败页', @@ -34,6 +35,7 @@ export default { 'menu.exception.trigger': '触发错误', 'menu.account': '个人页', 'menu.account.center': '个人中心', + 'menu.account.password': '密码修改', 'menu.account.settings': '个人设置', 'menu.account.trigger': '触发报错', 'menu.account.logout': '退出登录', diff --git a/src/locales/zh-CN/settings.js b/src/locales/zh-CN/settings.js index df8af43..be7f3c5 100644 --- a/src/locales/zh-CN/settings.js +++ b/src/locales/zh-CN/settings.js @@ -9,6 +9,8 @@ export default { 'app.settings.basic.email-message': '请输入您的邮箱!', 'app.settings.basic.nickname': '昵称', 'app.settings.basic.nickname-message': '请输入您的昵称!', + 'app.settings.basic.realname': '姓名', + 'app.settings.basic.realname-message': '请输入您的姓名!', 'app.settings.basic.profile': '个人简介', 'app.settings.basic.profile-message': '请输入个人简介!', 'app.settings.basic.profile-placeholder': '个人简介', @@ -21,6 +23,12 @@ export default { 'app.settings.basic.phone': '联系电话', 'app.settings.basic.phone-message': '请输入您的联系电话!', 'app.settings.basic.update': '更新基本信息', + 'app.settings.password.old': '旧密码', + 'app.settings.password.old-message': '请输入你的旧密码!', + 'app.settings.password.new': '新密码', + 'app.settings.password.new-message': '请输入你的新密码!', + 'app.settings.password.new1': '确认密码', + 'app.settings.password.new1-message': '请输入你的确认密码!', 'app.settings.security.strong': '强', 'app.settings.security.medium': '中', 'app.settings.security.weak': '弱', diff --git a/src/locales/zh-TW/login.js b/src/locales/zh-TW/login.js index 2505951..6c05cf9 100644 --- a/src/locales/zh-TW/login.js +++ b/src/locales/zh-TW/login.js @@ -1,5 +1,5 @@ export default { - 'app.login.tenantCode': '租戶編號', + 'app.login.tenantId': '租戶編號', 'app.login.userName': '賬戶', 'app.login.password': '密碼', 'app.login.message-invalid-credentials': '賬戶或密碼錯誤(admin/ant.design)', @@ -21,7 +21,7 @@ export default { 'app.register-result.view-mailbox': '查看郵箱', 'validation.email.required': '請輸入郵箱地址!', 'validation.email.wrong-format': '郵箱地址格式錯誤!', - 'validation.tenantCode.required': '請輸入租戶編號!', + 'validation.tenantId.required': '請輸入租戶編號!', 'validation.userName.required': '請輸入賬戶!', 'validation.password.required': '請輸入密碼!', 'validation.password.twice': '兩次輸入的密碼不匹配!', diff --git a/src/locales/zh-TW/menu.js b/src/locales/zh-TW/menu.js index 3bd46e2..68ed137 100644 --- a/src/locales/zh-TW/menu.js +++ b/src/locales/zh-TW/menu.js @@ -24,6 +24,7 @@ export default { 'menu.monitor.doc': '接口文檔', 'menu.tool': '研發工具', 'menu.tool.code': '代碼生成', + 'menu.tool.datasource': '數據源管理', 'menu.result': '結果頁', 'menu.result.success': '成功頁', 'menu.result.fail': '失敗頁', @@ -34,6 +35,7 @@ export default { 'menu.exception.trigger': '觸發錯誤', 'menu.account': '個人頁', 'menu.account.center': '個人中心', + 'menu.account.password': '密碼修改', 'menu.account.settings': '個人設置', 'menu.account.trigger': '觸發報錯', 'menu.account.logout': '退出登錄', diff --git a/src/locales/zh-TW/settings.js b/src/locales/zh-TW/settings.js index dd45151..66acea6 100644 --- a/src/locales/zh-TW/settings.js +++ b/src/locales/zh-TW/settings.js @@ -9,6 +9,8 @@ export default { 'app.settings.basic.email-message': '請輸入您的郵箱!', 'app.settings.basic.nickname': '昵稱', 'app.settings.basic.nickname-message': '請輸入您的昵稱!', + 'app.settings.basic.realname': '姓名', + 'app.settings.basic.realname-message': '請輸入您的姓名!', 'app.settings.basic.profile': '個人簡介', 'app.settings.basic.profile-message': '請輸入個人簡介!', 'app.settings.basic.profile-placeholder': '個人簡介', @@ -21,6 +23,12 @@ export default { 'app.settings.basic.phone': '聯系電話', 'app.settings.basic.phone-message': '請輸入您的聯系電話!', 'app.settings.basic.update': '更新基本信息', + 'app.settings.password.old': '舊密碼', + 'app.settings.password.old-message': '請輸入妳的舊密碼!', + 'app.settings.password.new': '新密碼', + 'app.settings.password.new-message': '請輸入妳的新密碼!', + 'app.settings.password.new1': '確認密碼', + 'app.settings.password.new1-message': '請輸入妳的確認密碼!', 'app.settings.security.strong': '強', 'app.settings.security.medium': '中', 'app.settings.security.weak': '弱', diff --git a/src/models/code.js b/src/models/code.js index b746a3c..6e2da3f 100644 --- a/src/models/code.js +++ b/src/models/code.js @@ -2,6 +2,8 @@ import { message } from 'antd'; import router from 'umi/router'; import { CODE_NAMESPACE } from '../actions/code'; import { list, submit, detail, remove } from '../services/code'; +import { select } from '../services/datasource'; +import { dict } from '../services/dict'; export default { namespace: CODE_NAMESPACE, @@ -10,6 +12,10 @@ export default { list: [], pagination: {}, }, + init: { + source: [], + category: [], + }, detail: {}, }, effects: { @@ -29,6 +35,19 @@ export default { }); } }, + *fetchInit({ payload }, { call, put }) { + const responseS = yield call(select, payload); + const responseC = yield call(dict, payload); + if (responseS.success && responseC.success) { + yield put({ + type: 'saveInit', + payload: { + source: responseS.data, + category: responseC.data, + }, + }); + } + }, *fetchDetail({ payload }, { call, put }) { const response = yield call(detail, payload); if (response.success) { @@ -71,6 +90,12 @@ export default { data: action.payload, }; }, + saveInit(state, action) { + return { + ...state, + init: action.payload, + }; + }, saveDetail(state, action) { return { ...state, diff --git a/src/models/datasource.js b/src/models/datasource.js new file mode 100644 index 0000000..e55dde7 --- /dev/null +++ b/src/models/datasource.js @@ -0,0 +1,87 @@ +import { message } from 'antd'; +import router from 'umi/router'; +import { DATASOURCE_NAMESPACE } from '../actions/datasource'; +import { list, submit, detail, remove } from '../services/datasource'; + +export default { + namespace: DATASOURCE_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('/tool/datasource'); + } + }, + *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: {}, + }; + }, + }, +}; diff --git a/src/models/user.js b/src/models/user.js index 2c9ef01..1fda883 100644 --- a/src/models/user.js +++ b/src/models/user.js @@ -1,7 +1,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 { query as queryUsers, list, submit, update, 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'; @@ -116,6 +116,13 @@ export default { router.push('/system/user'); } }, + *update({ payload }, { call }) { + const response = yield call(update, payload); + if (response.success) { + message.success('提交成功'); + router.push('/system/user'); + } + }, *remove({ payload }, { call }) { const { data: { keys }, diff --git a/src/pages/Account/Settings/BaseView.js b/src/pages/Account/Settings/BaseView.js index 388a835..045948d 100644 --- a/src/pages/Account/Settings/BaseView.js +++ b/src/pages/Account/Settings/BaseView.js @@ -1,106 +1,161 @@ -import React, { Component, Fragment } from 'react'; -import { formatMessage, FormattedMessage } from 'umi/locale'; -import { Form, Input, Upload, Select, Button } from 'antd'; -import { connect } from 'dva'; -import styles from './BaseView.less'; -import GeographicView from './GeographicView'; -import PhoneView from './PhoneView'; -// import { getTimeDistance } from '@/utils/utils'; +import React, { Component } from 'react'; +import { formatMessage } from 'umi/locale'; +import { Form, Input, Upload, Button, message, Icon, Card } from 'antd'; +import Panel from '../../../components/Panel'; +import { getUserInfo, update } from '../../../services/user'; +import { getToken } from '../../../utils/authority'; const FormItem = Form.Item; -const { Option } = Select; -// 头像组件 方便以后独立,增加裁剪之类的功能 -const AvatarView = ({ avatar }) => ( - -
- -
-
- avatar -
- -
- -
-
-
-); - -const validatorGeographic = (rule, value, callback) => { - const { province, city } = value; - if (!province.key) { - callback('Please input your province!'); - } - if (!city.key) { - callback('Please input your city!'); - } - callback(); -}; - -const validatorPhone = (rule, value, callback) => { - const values = value.split('-'); - if (!values[0]) { - callback('Please input your area code!'); - } - if (!values[1]) { - callback('Please input your phone number!'); - } - callback(); -}; - -@connect(({ user }) => ({ - currentUser: user.currentUser, -})) @Form.create() class BaseView extends Component { + state = { + userId: '', + avatar: '', + loading: false, + }; + componentDidMount() { this.setBaseInfo(); } setBaseInfo = () => { - const { currentUser, form } = this.props; - Object.keys(form.getFieldsValue()).forEach(key => { - const obj = {}; - obj[key] = currentUser[key] || null; - form.setFieldsValue(obj); + const { form } = this.props; + getUserInfo().then(resp => { + if (resp.success) { + const userInfo = resp.data; + Object.keys(form.getFieldsValue()).forEach(key => { + const obj = {}; + obj[key] = userInfo[key] || null; + form.setFieldsValue(obj); + }); + this.setState({ userId: userInfo.id, avatar: userInfo.avatar }); + } else { + message.error(resp.msg || '获取数据失败'); + } }); }; - getAvatarURL() { - const { currentUser } = this.props; - if (currentUser.avatar) { - return currentUser.avatar; + beforeUpload = file => { + const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'; + if (!isJpgOrPng) { + message.error('You can only upload JPG/PNG file!'); } - const url = 'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png'; - return url; - } + const isLt2M = file.size / 1024 / 1024 < 2; + if (!isLt2M) { + message.error('Image must smaller than 2MB!'); + } + return isJpgOrPng && isLt2M; + }; - getViewDom = ref => { - this.view = ref; + handleChange = info => { + if (info.file.status === 'uploading') { + this.setState({ loading: true }); + return; + } + if (info.file.status === 'done') { + this.setState({ loading: false, avatar: info.file.response.data.link }); + } + }; + + handleSubmit = e => { + e.preventDefault(); + const { form } = this.props; + const { userId, avatar } = this.state; + form.validateFieldsAndScroll((err, values) => { + if (!err) { + const params = { + id: userId, + ...values, + avatar, + }; + update(params).then(resp => { + if (resp.success) { + message.success(resp.msg); + } else { + message.error(resp.msg || '提交失败'); + } + }); + } + }); }; render() { const { form: { getFieldDecorator }, } = this.props; + + const { avatar, loading } = this.state; + + const formItemLayout = { + labelCol: { + xs: { span: 24 }, + sm: { span: 7 }, + }, + wrapperCol: { + xs: { span: 24 }, + sm: { span: 12 }, + md: { span: 10 }, + }, + }; + + const uploadProp = { + action: '/api/blade-resource/oss/endpoint/put-file', + headers: { + 'Blade-Auth': getToken(), + }, + }; + + const uploadButton = ( +
+ +
上传头像
+
+ ); + + const action = ( + + ); + return ( -
-
-
- - {getFieldDecorator('email', { + + + + + {getFieldDecorator('avatar', { rules: [ { required: true, - message: formatMessage({ id: 'app.settings.basic.email-message' }, {}), + message: formatMessage({ id: 'app.settings.basic.avatar' }, {}), }, ], - })()} + })( + + {avatar ? ( + avatar + ) : ( + uploadButton + )} + + )} - + {getFieldDecorator('name', { rules: [ { @@ -110,81 +165,42 @@ class BaseView extends Component { ], })()} - - {getFieldDecorator('profile', { + + {getFieldDecorator('realName', { rules: [ { required: true, - message: formatMessage({ id: 'app.settings.basic.profile-message' }, {}), - }, - ], - })( - - )} - - - {getFieldDecorator('country', { - rules: [ - { - required: true, - message: formatMessage({ id: 'app.settings.basic.country-message' }, {}), - }, - ], - })( - - )} - - - {getFieldDecorator('geographic', { - rules: [ - { - required: true, - message: formatMessage({ id: 'app.settings.basic.geographic-message' }, {}), - }, - { - validator: validatorGeographic, - }, - ], - })()} - - - {getFieldDecorator('address', { - rules: [ - { - required: true, - message: formatMessage({ id: 'app.settings.basic.address-message' }, {}), + message: formatMessage({ id: 'app.settings.basic.realname-message' }, {}), }, ], })()} - + {getFieldDecorator('phone', { rules: [ { required: true, message: formatMessage({ id: 'app.settings.basic.phone-message' }, {}), }, - { validator: validatorPhone }, ], - })()} + })()} - - -
-
- -
-
+ + {getFieldDecorator('email', { + rules: [ + { + required: true, + message: formatMessage({ id: 'app.settings.basic.email-message' }, {}), + }, + ], + })()} + + + + ); } } diff --git a/src/pages/Account/Settings/PasswordView.js b/src/pages/Account/Settings/PasswordView.js new file mode 100644 index 0000000..1e0e23d --- /dev/null +++ b/src/pages/Account/Settings/PasswordView.js @@ -0,0 +1,98 @@ +import React, { Component } from 'react'; +import { formatMessage } from 'umi/locale'; +import { Form, Input, Button, Card, message } from 'antd'; +import Panel from '../../../components/Panel'; +import { updatePassword } from '../../../services/user'; + +const FormItem = Form.Item; + +@Form.create() +class PasswordView extends Component { + handleSubmit = e => { + e.preventDefault(); + const { form } = this.props; + form.validateFieldsAndScroll((err, values) => { + if (!err) { + updatePassword(values).then(resp => { + if (resp.success) { + message.success(resp.msg); + } + }); + } + }); + }; + + render() { + const { + form: { getFieldDecorator }, + } = this.props; + + const formItemLayout = { + labelCol: { + xs: { span: 24 }, + sm: { span: 7 }, + }, + wrapperCol: { + xs: { span: 24 }, + sm: { span: 12 }, + md: { span: 10 }, + }, + }; + + const action = ( + + ); + + return ( + +
+ + + {getFieldDecorator('oldPassword', { + rules: [ + { + required: true, + message: formatMessage({ id: 'app.settings.password.old-message' }, {}), + }, + ], + })()} + + + {getFieldDecorator('newPassword', { + rules: [ + { + required: true, + message: formatMessage({ id: 'app.settings.password.new-message' }, {}), + }, + ], + })()} + + + {getFieldDecorator('newPassword1', { + rules: [ + { + required: true, + message: formatMessage({ id: 'app.settings.password.new1-message' }, {}), + }, + ], + })()} + + +
+
+ ); + } +} + +export default PasswordView; diff --git a/src/pages/Dashboard/Workplace.js b/src/pages/Dashboard/Workplace.js index 17c2431..a62290b 100644 --- a/src/pages/Dashboard/Workplace.js +++ b/src/pages/Dashboard/Workplace.js @@ -1,286 +1,223 @@ import React, { PureComponent } from 'react'; -import moment from 'moment'; -import { connect } from 'dva'; -import Link from 'umi/link'; -import { Row, Col, Card, List, Avatar } from 'antd'; +import { Card, Col, Collapse, Row } from 'antd'; +import styles from '../../layouts/Sword.less'; -import EditableLinkGroup from '@/components/EditableLinkGroup'; import PageHeaderWrapper from '@/components/PageHeaderWrapper'; -import styles from './Workplace.less'; +const { Panel } = Collapse; -const links = [ - { - title: '操作一', - href: '', - }, - { - title: '操作二', - href: '', - }, - { - title: '操作三', - href: '', - }, - { - title: '操作四', - href: '', - }, - { - title: '操作五', - href: '', - }, - { - title: '操作六', - href: '', - }, -]; -@connect(({ user, project, activities, loading }) => ({ - currentUser: user.currentUser, - project, - activities, - currentUserLoading: loading.effects['user/fetchCurrent'], - projectLoading: loading.effects['project/fetchNotice'], - activitiesLoading: loading.effects['activities/fetchList'], -})) class Workplace extends PureComponent { - componentDidMount() { - const { dispatch } = this.props; - dispatch({ - type: 'user/fetchCurrent', - }); - dispatch({ - type: 'project/fetchNotice', - }); - dispatch({ - type: 'activities/fetchList', - }); - } - - renderActivities() { - const { - activities: { list }, - } = this.props; - return list.map(item => { - const events = item.template.split(/@\{([^{}]*)\}/gi).map(key => { - if (item[key]) { - return ( - - {item[key].name} - - ); - } - return key; - }); - return ( - - } - title={ - - {item.user.name} -   - {events} - - } - description={ - - {moment(item.updatedAt).fromNow()} - - } - /> - - ); - }); - } - render() { - const { - currentUser, - currentUserLoading, - project: { notice }, - projectLoading, - activitiesLoading, - } = this.props; - - const pageHeaderContent = - currentUser && Object.keys(currentUser).length ? ( -
-
- -
-
-
- 您好, - {currentUser.name} - ,祝您开心每一天! -
-
我们用代码编写梦想,用梦想改变世界。
-
-
- ) : null; - - const extraContent = ( -
-
-

项目数

-

56

-
-
-

团队内排名

-

- 8 / 24 -

-
-
-

项目访问

-

2,223

-
-
- ); - return ( - - - - - -
- - - SpringBlade 2.0 - - 是一个基于 Spring Boot 2 & Spring Cloud Finchley & Mybatis - 等核心技术,用于快速构建中大型系统的基础框架。 - - - } - /> - - - - SpringBlade 企业版系列 - - 已通过长时间生产环境的考验,现将其拆分出基础模块进行开源,当前版本为:2.0.0。 - - - } - /> - - - - SpringBlade - - 技术交流群号:477853168。欢迎大家加入。 - - - } - /> - -
-
-
- - - {notice.map(item => ( - - - - - {item.title} -
- } - description={item.description} - /> - - - ))} - - - - - {}} links={links} linkElement={Link} /> - - -
- - - - - ChillZhuang - - - - - - DreamLu - - - - - - LengLeng - - - - - - LiXunHuan - - - + + + + +
+ Downloads + Build Status + Coverage Status + Downloads + + Downloads + + + Downloads +
-
- - + + + + + + +
1.Sword是SpringBlade前端UI系统
+
2.对现有的ant design pro库进行二次封装
+
3.100%兼容原生ant design pro库
+
4.配合后端代码生成系统可以快速搭建完整的功能模块
+
5.使用Sword可以大幅度提升开发效率,不再为重复工作发愁
+
+ +
1.BladeX是一款精心设计的微服务架构,提供 SpringCloud 全套解决方案
+
2.开源中国首批完美集成 SpringCloud Alibaba 系列组件的微服务架构
+
3.基于稳定生产的商业项目升级优化而来,更加贴近企业级的需求
+
4.追求企业开发更加高效,部署更加方便,生产更加稳定
+
5.GVP-码云最有价值开源项目
+
6.BladeX授权地址:点击授权
+
+ +
1.经历过较长的线上生产,积累了很多企业痛点的解决方案。
+
2.一套代码兼容MySql、Oracle、PostgreSQL,适应企业各种不同场景的需求。
+
3.集成了很多企业急切所需的例如多租户、Oauth2授权认证、工作流、分布式事务等等功能。
+
4.深度定制了Flowable工作流,完美支持SpringCloud分布式服务的场景,以远程调用的方式进行操作。
+
5.升级了核心驱动,新功能完全可以开箱即用,而开源版需要自己再花时间进行集成,需要花掉更多的时间成本。
+
6.拥抱微服务时代,很多企业由于项目转型或升级,传统的技术已然不能满足,反而会花更多成本,而BladeX就是为此而生。
+
7.同时提供SpringCloud版本和SpringBoot版本,两个版本的api可以与Sword和Saber无缝对接,为小型项目至大型项目保驾护航。
+
8.授权购买即永久,源码没有混淆,后续升级完全免费。企业只需花很少的钱即可获得一整套成熟的解决方案,你还在等什么?
+
+ +
1.前后端分离-采用前后端分离模式,前端提供两套架构,Sword基于React,Saber基于Vue
+
2. 分布式单体式后端架构-提供两套后端架构,基于SpringCloud的分布式架构以及基于SpringBoot的单体式架构
+
3.API完全兼容-两套后端架构与两套前端架构,共四套架构可以任意组合,所有API完全兼容
+
4.前后端代码生成-定制针对两套前端与后端的代码生成模板,轻松生成整个模块的前后端代码,减少重复工作量
+
5.组件化、插件化架构-针对功能深度定制各个starter,引入开箱即用,为整个架构解耦,提升效率
+
6.Nacos-集成阿里巴巴的Nacos完成统一的服务注册与配置
+
7.Sentinel-集成Sentinel从流量控制、熔断降级、系统负载等多个维度保护服务的稳定性
+
8.Dubbo-完美集成Dubbo最新版,支持远程RPC调用
+
9.多租户系统-完整的SaaS多租户架构
+
10.Oauth2-集成Oauth2协议,完美支持多终端的接入与认证授权
+
11.工作流-深度定制SpringCloud分布式场景的Flowable工作流,为复杂流程保驾护航。同时提供SpringBoot集成版本
+
12.独立流程设计器-提供独立的完全汉化的流程设计器,轻松定制流程模型
+
13.动态网关-集成基于Nacos的轻量级、高拓展性动态网关
+
14.动态聚合文档-实现基于Nacos的Swagger SpringCloud聚合文档
+
15.分布式文件服务-集成minio、qiniu、alioss等优秀的第三方,提供便捷的文件上传与管理
+
16.多租户对象存储系统-在SaaS系统中,各租户可自行配置文件上传至自己的私有OSS
+
17.权限管理-精心设计的权限管理方案,角色权限精确到按钮
+
18.动态数据权限-高度灵活的动态数据权限,提供注解+Web可视化两种配置方式,Web配置无需重启直接生效
+
19.动态接口权限-高度灵活的动态接口权限,提供注解+Web可视化两种配置方式,Web配置无需重启直接生效
+
20.多租户顶部菜单配置-提供给每个租户独立的顶部菜单配置模块,可以自定义顶部菜单切换
+
21.主流数据库兼容-一套代码完全兼容Mysql、Postgresql、Oracle三大主流数据库
+
22.动态网关鉴权-基于Nacos的动态网关鉴权,可在线配置,实时生效
+
23.全能代码生成器-支持自定义模型、模版 、业务建模,支持多种模板引擎,在线配置。大幅度提升开发效率,不再为重复工作发愁。
+
24.Seata分布式事务-定制集成Seata,支持分布式事务,无代码侵入,不失灵活与简洁
+
25.未完待续...
+
+ +
1.接BladeX系列架构的定制服务
+
2.接3个月以内工期的react、vue、springboot、springcloud、app、小程序等软件定制服务
+
3.有意向请联系唯一指定QQ:85088620
+
+
+ + + + +
1.增加示例工程,增加多种常见场景的解决方案
+
2.增加不同包名运行的示例
+
3.增加多数据源调用运行的示例
+
4.增加自定义加载Naocs配置文件的示例
+
5.增加根据Nacos命名空间读取配置、注册服务的示例
+
6.修复Condition类没有过滤分页字段的问题
+
7.拆分CommonConstant出LauncherConstant
+
+ +
1.封装集成zipkin,支持分布式链路追踪
+
2.seata升级至0.9.0,解决部分分布式事务遇到的bug
+
3.springboot版本升级至2.1.9
+
+ +
1.增加个人中心,支持用户信息自定义修改
+
2.增加网关鉴权配置示例
+
3.token的SIGN_KEY修改为一致
+
4.admin模块增加对seata服务的过滤
+
5.blade-tool增加部分工具类方法
+
+ +
1.增加网关动态鉴权
+
2.secure安全模块token校验默认关闭,交由网关处理
+
3.boot版本开启secure token校验功能
+
4.优化blade-gateway代码逻辑
+
5.修复blade-resource无法启动的问题
+
+ +
1.封装集成seata,支持分布式事务
+
2.重写blade-core-cloud模块,增强cloud场景支持
+
3.增加hystrix自动fallback功能
+
4.升级springboot至2.1.8.RELEASE
+
5.升级springcloud至Greenwich.SR3
+
+ +
1.升级SpringBoot至2.1.7
+
2.代码生成增加多数据源配置
+
3.增强代码生成功能,支持可选基础业务、包装器配置
+
4.优化代码生成模板
+
+ +
1.升级AlibabaCloud毕业版本
+
2.升级支持Naocs 1.1.0、Sentinel 1.6.3
+
3.租户系统的tenantCode统一更改为tenantId
+
4.优化代码生成模板
+
5.优化mybatis-plus新版配置
+
6.修复排序字段sql注入问题
+
+ +
1.重构令牌发放逻辑,可自定义令牌类型,增强可拓展性
+
2.增加动态配置token过期时间、令牌续期功能
+
3.增加GateWay动态聚合文档功能,简化配置
+
4.优化Wrapper定义,代码更加简洁
+
5.Swagger增加多包扫描
+
6.使用 Swagger-Bootstrap-UI 最新版排序注解
+
7.升级 SpringBoot 2.1.6,SpringCloud Greenwich.SR2
+
8.升级 Mybatis-Plus 3.1.2
+
9.修复排序字段可能导致的sql注入问题
+
10.修复部分缓存清除失效的问题
+
+ +
1.增加七牛云oss-starter
+
2.增加blade-resource模块,对外提供服务,支持分布式下的oss场景
+
3.LauncherService增加排序功能
+
4.增加单元测试starter,可在启动过程中便捷地指定profile以及启动参数
+
5.增加指定启动参数的单元测试demo
+
6.优化docker脚本配置
+
+ +
1.升级 SpringBoot 2.1.5
+
2.前端框架Saber升级 element-ui 2.8.2
+
3.Saber业务代码升级
+
4.优化Saber代码生成模板
+
5.统一日志业务表基础字段
+
6.优化租户过滤逻辑
+
7.BaseEntity放开主键限制,子类可自定义主键类型
+
8.XssFilter增加放行配置,可配置放行微信api接口
+
+ +
1.升级 SpringCloud Greenwich
+
2.升级 SpringCloud Alibaba 组件版本为0.9.0.RELEASE,支持最新版本的nacos与sentinel
+
3.升级 SpringBoot 2.1.4
+
4.升级 mysql 驱动版本
+
5.优化 LauncherService 关于环境的判断逻辑
+
6.修复 blade-core-log 在部分情况下获取request为空的问题
+
7.修复多租户插件判断租户过滤的逻辑
+
8.修复请求日志打印插件部分格式空指针的问题
+
9.降低nacos心跳日志等级,关闭心跳日志显示
+
+ +
1.增加多终端令牌认证系统
+
2.增加多租户开关
+
3.修复部分模块没有筛选已删除的问题
+
4.调整角色分配会越权的问题
+
5.优化部署脚本
+
+ +
1.升级为SaaS多租户系统
+
2.优化代码生成逻辑
+
3.代码生成增加菜单sql
+
4.增加SysClient,提供系统信息远程调用
+
5.优化部署脚本,增加前端部署实例
+
6.增加父子角色过滤,使得角色无法越权配置
+
+ +
1.SpringBlade 2.0 是由一个商业级项目升级优化而来的SpringCloud微服务架构,采用Java8 API重构了业务代码,完全遵循阿里巴巴编码规范
+
2.采用Spring Boot 2 、Spring Cloud Greenwich 、Mybatis 等核心技术,用于快速搭建企业级的微服务系统平台
+
3.SpringBlade 致力于创造新颖的开发模式,将开发中遇到的痛点、生产中所踩的坑整理归纳,并将解决方案都融合到框架中
+
+
+ +
+
); } diff --git a/src/pages/Login/Login.js b/src/pages/Login/Login.js index 96a19dc..e790394 100644 --- a/src/pages/Login/Login.js +++ b/src/pages/Login/Login.js @@ -1,12 +1,12 @@ import React, { Component } from 'react'; import { connect } from 'dva'; import { formatMessage, FormattedMessage } from 'umi/locale'; -import { Checkbox, Alert } from 'antd'; +import { Checkbox, Alert, notification, Icon } from 'antd'; import Login from '../../components/Login'; import styles from './Login.less'; import { tenantMode } from '../../defaultSettings'; -const { Tab, TenantCode, UserName, Password, Submit } = Login; +const { Tab, TenantId, UserName, Password, Submit } = Login; @connect(({ login, loading }) => ({ login, @@ -18,6 +18,44 @@ class LoginPage extends Component { autoLogin: true, }; + componentWillMount() { + notification.config({ + placement: 'bottomRight', + }); + notification.destroy(); + notification.open({ + message: '手册信息', + description: ( +
+

Sword开发手册:点击查看

+

SpringBlade开发手册:点击查看

+
+ ), + icon: , + duration: 0, + }); + setTimeout(() => { + notification.open({ + message: '授权信息', + description: ( +
+

欢迎使用Sword!

+

该系统可用BladeX增强开发,

+

若要商用强烈推荐高度定制的商业化框架,具体授权信息请访问如下地址。

+

+ BladeX 授权地址: + + 点击授权 + +

+
+ ), + icon: , + duration: 0, + }); + }, 500); + } + onTabChange = type => { this.setState({ type }); }; @@ -82,19 +120,21 @@ class LoginPage extends Component { !submitting && this.renderMessage(formatMessage({ id: 'app.login.message-invalid-credentials' }))} {tenantMode ? ( - ) : null} { const { dispatch } = this.props; dispatch(CODE_LIST(params)); + this.setState({ params }); }; onSelectRow = rows => { @@ -60,6 +62,36 @@ class Code extends PureComponent { }); }; + copyCode = keys => { + const { params } = this.state; + const { dispatch } = this.props; + if (keys.length === 0) { + message.warn('请先选择一条数据!'); + return; + } + if (keys.length > 1) { + message.warn('只能选择一条数据!'); + return; + } + Modal.confirm({ + title: '代码配置复制确认', + content: '是否复制选中模块的配置?', + okText: '确定', + okType: 'danger', + cancelText: '取消', + async onOk() { + const response = await copyCodes({ id: keys[0] }); + if (response.success) { + message.success(response.msg); + dispatch(CODE_LIST(params)); + } else { + message.error(response.msg || '复制失败'); + } + }, + onCancel() {}, + }); + }; + // ============ 查询表单 =============== renderSearchForm = onReset => { const { form } = this.props; @@ -102,6 +134,19 @@ class Code extends PureComponent { ); + renderActionButton = (keys, rows) => ( + + + { + this.copyCode(keys, rows); + }} + > + 复制 + + + ); + render() { const code = 'code'; @@ -147,6 +192,7 @@ class Code extends PureComponent { onSearch={this.handleSearch} renderSearchForm={this.renderSearchForm} renderLeftButton={this.renderLeftButton} + renderActionButton={this.renderActionButton} loading={loading} data={data} columns={columns} diff --git a/src/pages/System/Code/CodeAdd.js b/src/pages/System/Code/CodeAdd.js index b7e30af..e1cacdd 100644 --- a/src/pages/System/Code/CodeAdd.js +++ b/src/pages/System/Code/CodeAdd.js @@ -1,17 +1,24 @@ import React, { PureComponent } from 'react'; -import { Form, Input, Card, Button } from 'antd'; +import { Form, Input, Card, Button, Row, Col, Radio, Select } from 'antd'; import { connect } from 'dva'; import Panel from '../../../components/Panel'; import styles from '../../../layouts/Sword.less'; -import { CODE_SUBMIT } from '../../../actions/code'; +import { CODE_INIT, CODE_SUBMIT } from '../../../actions/code'; const FormItem = Form.Item; +const RadioGroup = Radio.Group; -@connect(({ loading }) => ({ +@connect(({ code, loading }) => ({ + code, submitting: loading.effects['code/submit'], })) @Form.create() class CodeAdd extends PureComponent { + componentWillMount() { + const { dispatch } = this.props; + dispatch(CODE_INIT()); + } + handleSubmit = e => { e.preventDefault(); const { dispatch, form } = this.props; @@ -25,18 +32,27 @@ class CodeAdd extends PureComponent { render() { const { form: { getFieldDecorator }, + code: { init }, submitting, } = this.props; + const { source, category } = init; + const formItemLayout = { labelCol: { - xs: { span: 24 }, - sm: { span: 7 }, + span: 8, }, wrapperCol: { - xs: { span: 24 }, - sm: { span: 12 }, - md: { span: 10 }, + span: 16, + }, + }; + + const formAllItemLayout = { + labelCol: { + span: 4, + }, + wrapperCol: { + span: 20, }, }; @@ -48,88 +64,178 @@ class CodeAdd extends PureComponent { return ( -
+ - - {getFieldDecorator('codeName', { - rules: [ - { - required: true, - message: '请输入模块名', - }, - ], - })()} - - - {getFieldDecorator('serviceName', { - rules: [ - { - required: true, - message: '请输入服务名', - }, - ], - })()} - - - {getFieldDecorator('tableName', { - rules: [ - { - required: true, - message: '请输入表名', - }, - ], - })()} - - - {getFieldDecorator('tablePrefix', { - rules: [ - { - required: true, - message: '请输入表前缀名', - }, - ], - })()} - - - {getFieldDecorator('pkName', { - rules: [ - { - required: true, - message: '请输入主键名', - }, - ], - })()} - - - {getFieldDecorator('packageName', { - rules: [ - { - required: true, - message: '请输入包名', - }, - ], - })()} - - - {getFieldDecorator('apiPath', { - rules: [ - { - required: true, - message: '请输入后端生成路径', - }, - ], - })()} - - - {getFieldDecorator('webPath', { - rules: [ - { - required: true, - message: '请输入前端生成路径', - }, - ], - })()} - + + + + {getFieldDecorator('datasourceId', { + rules: [ + { + required: true, + message: '请选择数据源', + }, + ], + })( + + )} + + + + + + + {getFieldDecorator('codeName', { + rules: [ + { + required: true, + message: '请输入模块名', + }, + ], + })()} + + + + + {getFieldDecorator('serviceName', { + rules: [ + { + required: true, + message: '请输入服务名', + }, + ], + })()} + + + + + + + {getFieldDecorator('tableName', { + rules: [ + { + required: true, + message: '请输入表名', + }, + ], + })()} + + + + + {getFieldDecorator('tablePrefix', { + rules: [ + { + required: true, + message: '请输入表前缀名', + }, + ], + })()} + + + + + + + {getFieldDecorator('pkName', { + rules: [ + { + required: true, + message: '请输入主键名', + }, + ], + })()} + + + + + {getFieldDecorator('packageName', { + rules: [ + { + required: true, + message: '请输入包名', + }, + ], + })()} + + + + + + + {getFieldDecorator('baseMode', { + rules: [ + { + required: true, + message: '请配置基础业务', + }, + ], + })( + + {category.map(d => ( + + {d.dictValue} + + ))} + + )} + + + + + {getFieldDecorator('wrapMode', { + rules: [ + { + required: true, + message: '请配置包装器', + }, + ], + })( + + {category.map(d => ( + + {d.dictValue} + + ))} + + )} + + + + + + + {getFieldDecorator('apiPath', { + rules: [ + { + required: true, + message: '请输入后端生成路径', + }, + ], + })()} + + + + + + + {getFieldDecorator('webPath', { + rules: [ + { + required: true, + message: '请输入前端生成路径', + }, + ], + })()} + + +
diff --git a/src/pages/System/Code/CodeEdit.js b/src/pages/System/Code/CodeEdit.js index e0b17be..d294ea5 100644 --- a/src/pages/System/Code/CodeEdit.js +++ b/src/pages/System/Code/CodeEdit.js @@ -1,11 +1,12 @@ import React, { PureComponent } from 'react'; -import { Form, Input, Card, Button } from 'antd'; +import { Form, Input, Card, Button, Col, Row, Select, Radio } from 'antd'; import { connect } from 'dva'; import Panel from '../../../components/Panel'; import styles from '../../../layouts/Sword.less'; -import { CODE_DETAIL, CODE_SUBMIT } from '../../../actions/code'; +import { CODE_DETAIL, CODE_INIT, CODE_SUBMIT } from '../../../actions/code'; const FormItem = Form.Item; +const RadioGroup = Radio.Group; @connect(({ code, loading }) => ({ code, @@ -21,6 +22,7 @@ class CodeEdit extends PureComponent { }, } = this.props; dispatch(CODE_DETAIL(id)); + dispatch(CODE_INIT()); } handleSubmit = e => { @@ -38,7 +40,6 @@ class CodeEdit extends PureComponent { id, ...values, }; - console.log(params); dispatch(CODE_SUBMIT(params)); } }); @@ -47,19 +48,27 @@ class CodeEdit extends PureComponent { render() { const { form: { getFieldDecorator }, - code: { detail }, + code: { detail, init }, submitting, } = this.props; + const { source, category } = init; + const formItemLayout = { labelCol: { - xs: { span: 24 }, - sm: { span: 7 }, + span: 8, }, wrapperCol: { - xs: { span: 24 }, - sm: { span: 12 }, - md: { span: 10 }, + span: 16, + }, + }; + + const formAllItemLayout = { + labelCol: { + span: 4, + }, + wrapperCol: { + span: 20, }, }; @@ -71,96 +80,190 @@ class CodeEdit extends PureComponent { return ( -
+ - - {getFieldDecorator('codeName', { - rules: [ - { - required: true, - message: '请输入模块名', - }, - ], - initialValue: detail.codeName, - })()} - - - {getFieldDecorator('serviceName', { - rules: [ - { - required: true, - message: '请输入服务名', - }, - ], - initialValue: detail.serviceName, - })()} - - - {getFieldDecorator('tableName', { - rules: [ - { - required: true, - message: '请输入表名', - }, - ], - initialValue: detail.tableName, - })()} - - - {getFieldDecorator('tablePrefix', { - rules: [ - { - required: true, - message: '请输入表前缀名', - }, - ], - initialValue: detail.tablePrefix, - })()} - - - {getFieldDecorator('pkName', { - rules: [ - { - required: true, - message: '请输入主键名', - }, - ], - initialValue: detail.pkName, - })()} - - - {getFieldDecorator('packageName', { - rules: [ - { - required: true, - message: '请输入包名', - }, - ], - initialValue: detail.packageName, - })()} - - - {getFieldDecorator('apiPath', { - rules: [ - { - required: true, - message: '请输入后端生成路径', - }, - ], - initialValue: detail.apiPath, - })()} - - - {getFieldDecorator('webPath', { - rules: [ - { - required: true, - message: '请输入前端生成路径', - }, - ], - initialValue: detail.webPath, - })()} - + + + + {getFieldDecorator('datasourceId', { + rules: [ + { + required: true, + message: '请选择数据源', + }, + ], + initialValue: detail.datasourceId, + })( + + )} + + + + + + + {getFieldDecorator('codeName', { + rules: [ + { + required: true, + message: '请输入模块名', + }, + ], + initialValue: detail.codeName, + })()} + + + + + {getFieldDecorator('serviceName', { + rules: [ + { + required: true, + message: '请输入服务名', + }, + ], + initialValue: detail.serviceName, + })()} + + + + + + + {getFieldDecorator('tableName', { + rules: [ + { + required: true, + message: '请输入表名', + }, + ], + initialValue: detail.tableName, + })()} + + + + + {getFieldDecorator('tablePrefix', { + rules: [ + { + required: true, + message: '请输入表前缀名', + }, + ], + initialValue: detail.tablePrefix, + })()} + + + + + + + {getFieldDecorator('pkName', { + rules: [ + { + required: true, + message: '请输入主键名', + }, + ], + initialValue: detail.pkName, + })()} + + + + + {getFieldDecorator('packageName', { + rules: [ + { + required: true, + message: '请输入包名', + }, + ], + initialValue: detail.packageName, + })()} + + + + + + + + {getFieldDecorator('baseMode', { + rules: [ + { + required: true, + message: '请配置基础业务', + }, + ], + initialValue: detail.baseMode, + })( + + {category.map(d => ( + + {d.dictValue} + + ))} + + )} + + + + + {getFieldDecorator('wrapMode', { + rules: [ + { + required: true, + message: '请配置包装器', + }, + ], + initialValue: detail.wrapMode, + })( + + {category.map(d => ( + + {d.dictValue} + + ))} + + )} + + + + + + + {getFieldDecorator('apiPath', { + rules: [ + { + required: true, + message: '请输入后端生成路径', + }, + ], + initialValue: detail.apiPath, + })()} + + + + + + + {getFieldDecorator('webPath', { + rules: [ + { + required: true, + message: '请输入前端生成路径', + }, + ], + initialValue: detail.webPath, + })()} + + +
diff --git a/src/pages/System/Code/CodeView.js b/src/pages/System/Code/CodeView.js index 48edd72..d9ca11e 100644 --- a/src/pages/System/Code/CodeView.js +++ b/src/pages/System/Code/CodeView.js @@ -1,6 +1,6 @@ import React, { PureComponent } from 'react'; import router from 'umi/router'; -import { Form, Card, Button } from 'antd'; +import { Form, Card, Button, Row, Col } from 'antd'; import { connect } from 'dva'; import Panel from '../../../components/Panel'; import styles from '../../../layouts/Sword.less'; @@ -39,13 +39,19 @@ class CodeView extends PureComponent { const formItemLayout = { labelCol: { - xs: { span: 24 }, - sm: { span: 7 }, + span: 8, }, wrapperCol: { - xs: { span: 24 }, - sm: { span: 12 }, - md: { span: 10 }, + span: 16, + }, + }; + + const formAllItemLayout = { + labelCol: { + span: 4, + }, + wrapperCol: { + span: 20, }, }; @@ -57,32 +63,58 @@ class CodeView extends PureComponent { return ( -
+ - - {detail.codeName} - - - {detail.serviceName} - - - {detail.tableName} - - - {detail.tablePrefix} - - - {detail.pkName} - - - {detail.packageName} - - - {detail.apiPath} - - - {detail.webPath} - + + + + {detail.codeName} + + + + + {detail.serviceName} + + + + + + + {detail.tableName} + + + + + {detail.tablePrefix} + + + + + + + {detail.pkName} + + + + + {detail.packageName} + + + + + + + {detail.apiPath} + + + + + + + {detail.webPath} + + +
diff --git a/src/pages/System/DataSource/DataSource.js b/src/pages/System/DataSource/DataSource.js new file mode 100644 index 0000000..89a4918 --- /dev/null +++ b/src/pages/System/DataSource/DataSource.js @@ -0,0 +1,91 @@ +import React, { PureComponent } from 'react'; +import { connect } from 'dva'; +import { Button, Col, Form, Input, Row } from 'antd'; +import Panel from '../../../components/Panel'; +import { DATASOURCE_LIST } from '../../../actions/datasource'; +import Grid from '../../../components/Sword/Grid'; + +const FormItem = Form.Item; + +@connect(({ datasource, loading }) => ({ + datasource, + loading: loading.models.datasource, +})) +@Form.create() +class DataSource extends PureComponent { + // ============ 查询 =============== + handleSearch = params => { + const { dispatch } = this.props; + dispatch(DATASOURCE_LIST(params)); + }; + + // ============ 查询表单 =============== + renderSearchForm = onReset => { + const { form } = this.props; + const { getFieldDecorator } = form; + + return ( + + + + {getFieldDecorator('name')()} + + + +
+ + +
+ +
+ ); + }; + + render() { + const code = 'datasource'; + + const { + form, + loading, + datasource: { data }, + } = this.props; + + const columns = [ + { + title: '名称', + dataIndex: 'name', + }, + { + title: '驱动类', + dataIndex: 'driverClass', + }, + { + title: '用户名', + dataIndex: 'username', + }, + { + title: '备注', + dataIndex: 'remark', + }, + ]; + + return ( + + + + ); + } +} +export default DataSource; diff --git a/src/pages/System/DataSource/DataSourceAdd.js b/src/pages/System/DataSource/DataSourceAdd.js new file mode 100644 index 0000000..b6b4009 --- /dev/null +++ b/src/pages/System/DataSource/DataSourceAdd.js @@ -0,0 +1,132 @@ +import React, { PureComponent } from 'react'; +import { Form, Input, Card, Button, Select } from 'antd'; +import { connect } from 'dva'; +import Panel from '../../../components/Panel'; +import styles from '../../../layouts/Sword.less'; +import { DATASOURCE_SUBMIT } from '../../../actions/datasource'; + +const FormItem = Form.Item; + +@connect(({ loading }) => ({ + submitting: loading.effects['datasource/submit'], +})) +@Form.create() +class DataSourceAdd extends PureComponent { + handleSubmit = e => { + e.preventDefault(); + const { dispatch, form } = this.props; + form.validateFieldsAndScroll((err, values) => { + if (!err) { + dispatch(DATASOURCE_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 = ( + + ); + + return ( + +
+ + + {getFieldDecorator('name', { + rules: [ + { + required: true, + message: '请输入名称', + }, + ], + })()} + + + {getFieldDecorator('driverClass', { + rules: [ + { + required: true, + message: '请输入驱动类', + }, + ], + })( + + )} + + + {getFieldDecorator('url', { + rules: [ + { + required: true, + message: '请输入连接地址', + }, + ], + })()} + + + {getFieldDecorator('username', { + rules: [ + { + required: true, + message: '请输入用户名', + }, + ], + })()} + + + {getFieldDecorator('password', { + rules: [ + { + required: true, + message: '请输入密码', + }, + ], + })()} + + + {getFieldDecorator('remark', { + rules: [ + { + required: true, + message: '请输入备注', + }, + ], + })()} + + +
+
+ ); + } +} + +export default DataSourceAdd; diff --git a/src/pages/System/DataSource/DataSourceEdit.js b/src/pages/System/DataSource/DataSourceEdit.js new file mode 100644 index 0000000..fb60aa0 --- /dev/null +++ b/src/pages/System/DataSource/DataSourceEdit.js @@ -0,0 +1,161 @@ +import React, { PureComponent } from 'react'; +import { Form, Input, Card, Button, Select } from 'antd'; +import { connect } from 'dva'; +import Panel from '../../../components/Panel'; +import styles from '../../../layouts/Sword.less'; +import { DATASOURCE_DETAIL, DATASOURCE_SUBMIT } from '../../../actions/datasource'; + +const FormItem = Form.Item; + +@connect(({ datasource, loading }) => ({ + datasource, + submitting: loading.effects['datasource/submit'], +})) +@Form.create() +class DataSourceEdit extends PureComponent { + componentWillMount() { + const { + dispatch, + match: { + params: { id }, + }, + } = this.props; + dispatch(DATASOURCE_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(DATASOURCE_SUBMIT(params)); + } + }); + }; + + render() { + const { + form: { getFieldDecorator }, + datasource: { 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 = ( + + ); + + return ( + +
+ + + {getFieldDecorator('name', { + rules: [ + { + required: true, + message: '请输入名称', + }, + ], + initialValue: detail.name, + })()} + + + {getFieldDecorator('driverClass', { + rules: [ + { + required: true, + message: '请输入驱动类', + }, + ], + initialValue: detail.driverClass, + })( + + )} + + + {getFieldDecorator('url', { + rules: [ + { + required: true, + message: '请输入连接地址', + }, + ], + initialValue: detail.url, + })()} + + + {getFieldDecorator('username', { + rules: [ + { + required: true, + message: '请输入用户名', + }, + ], + initialValue: detail.username, + })()} + + + {getFieldDecorator('password', { + rules: [ + { + required: true, + message: '请输入密码', + }, + ], + initialValue: detail.password, + })()} + + + {getFieldDecorator('remark', { + rules: [ + { + required: true, + message: '请输入备注', + }, + ], + initialValue: detail.remark, + })()} + + +
+
+ ); + } +} + +export default DataSourceEdit; diff --git a/src/pages/System/DataSource/DataSourceView.js b/src/pages/System/DataSource/DataSourceView.js new file mode 100644 index 0000000..901f7c5 --- /dev/null +++ b/src/pages/System/DataSource/DataSourceView.js @@ -0,0 +1,86 @@ +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 { DATASOURCE_DETAIL } from '../../../actions/datasource'; + +const FormItem = Form.Item; + +@connect(({ datasource }) => ({ + datasource, +})) +@Form.create() +class DataSourceView extends PureComponent { + componentWillMount() { + const { + dispatch, + match: { + params: { id }, + }, + } = this.props; + dispatch(DATASOURCE_DETAIL(id)); + } + + handleEdit = () => { + const { + match: { + params: { id }, + }, + } = this.props; + router.push(`/tool/datasource/edit/${id}`); + }; + + render() { + const { + datasource: { detail }, + } = this.props; + + const formItemLayout = { + labelCol: { + xs: { span: 24 }, + sm: { span: 7 }, + }, + wrapperCol: { + xs: { span: 24 }, + sm: { span: 12 }, + md: { span: 10 }, + }, + }; + + const action = ( + + ); + + return ( + +
+ + + {detail.name} + + + {detail.driverClass} + + + {detail.url} + + + {detail.username} + + + {detail.password} + + + {detail.remark} + + +
+
+ ); + } +} +export default DataSourceView; diff --git a/src/pages/System/Dept/Dept.js b/src/pages/System/Dept/Dept.js index f859afd..652b6c9 100644 --- a/src/pages/System/Dept/Dept.js +++ b/src/pages/System/Dept/Dept.js @@ -33,8 +33,8 @@ class Dept extends PureComponent { - - {getFieldDecorator('tenantCode')()} + + {getFieldDecorator('tenantId')()} @@ -67,8 +67,8 @@ class Dept extends PureComponent { const columns = [ { - title: '租户编号', - dataIndex: 'tenantCode', + title: '租户ID', + dataIndex: 'tenantId', }, { title: '部门名称', diff --git a/src/pages/System/Role/Role.js b/src/pages/System/Role/Role.js index 82ecc51..229a788 100644 --- a/src/pages/System/Role/Role.js +++ b/src/pages/System/Role/Role.js @@ -124,8 +124,8 @@ class Role extends PureComponent { - - {getFieldDecorator('tenantCode')()} + + {getFieldDecorator('tenantId')()} @@ -178,8 +178,8 @@ class Role extends PureComponent { const columns = [ { - title: '租户编号', - dataIndex: 'tenantCode', + title: '租户ID', + dataIndex: 'tenantId', }, { title: '角色名称', diff --git a/src/pages/System/Tenant/Tenant.js b/src/pages/System/Tenant/Tenant.js index c0aba03..0925fe4 100644 --- a/src/pages/System/Tenant/Tenant.js +++ b/src/pages/System/Tenant/Tenant.js @@ -27,8 +27,8 @@ class Tenant extends PureComponent { return ( - - {getFieldDecorator('tenantCode')()} + + {getFieldDecorator('tenantId')()} @@ -66,8 +66,8 @@ class Tenant extends PureComponent { const columns = [ { - title: '租户编号', - dataIndex: 'tenantCode', + title: '租户ID', + dataIndex: 'tenantId', }, { title: '租户名称', diff --git a/src/pages/System/Tenant/TenantView.js b/src/pages/System/Tenant/TenantView.js index 78b75b0..b4f6e65 100644 --- a/src/pages/System/Tenant/TenantView.js +++ b/src/pages/System/Tenant/TenantView.js @@ -59,8 +59,8 @@ class TenantView extends PureComponent {
- - {detail.tenantCode} + + {detail.tenantId} {detail.tenantName} diff --git a/src/pages/System/User/User.js b/src/pages/System/User/User.js index 9be9608..0fdcfe3 100644 --- a/src/pages/System/User/User.js +++ b/src/pages/System/User/User.js @@ -175,8 +175,8 @@ class User extends PureComponent { const columns = [ { - title: '租户编号', - dataIndex: 'tenantCode', + title: '租户ID', + dataIndex: 'tenantId', }, { title: '登录账号', diff --git a/src/pages/System/User/UserAdd.js b/src/pages/System/User/UserAdd.js index 6728ff5..866c5a5 100644 --- a/src/pages/System/User/UserAdd.js +++ b/src/pages/System/User/UserAdd.js @@ -46,7 +46,7 @@ class UserAdd extends PureComponent { handleChange = value => { const { dispatch, form } = this.props; form.resetFields(['roleId', 'deptId']); - dispatch(USER_CHANGE_INIT({ tenantCode: value })); + dispatch(USER_CHANGE_INIT({ tenantId: value })); }; render() { @@ -104,7 +104,7 @@ class UserAdd extends PureComponent { - {getFieldDecorator('tenantCode', { + {getFieldDecorator('tenantId', { rules: [ { required: true, @@ -122,7 +122,7 @@ class UserAdd extends PureComponent { placeholder="请选择所属租户" > {tenantList.map(d => ( - + {d.tenantName} ))} diff --git a/src/pages/System/User/UserEdit.js b/src/pages/System/User/UserEdit.js index 5591d3f..c74aacb 100644 --- a/src/pages/System/User/UserEdit.js +++ b/src/pages/System/User/UserEdit.js @@ -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_CHANGE_INIT, USER_DETAIL, USER_INIT, USER_SUBMIT } from '../../../actions/user'; +import { USER_CHANGE_INIT, USER_DETAIL, USER_INIT, USER_UPDATE } from '../../../actions/user'; import { tenantMode } from '../../../defaultSettings'; const FormItem = Form.Item; @@ -45,7 +45,7 @@ class UserEdit extends PureComponent { deptId: func.join(values.deptId), birthday: func.format(values.birthday), }; - dispatch(USER_SUBMIT(params)); + dispatch(USER_UPDATE(params)); } }); }; @@ -53,7 +53,7 @@ class UserEdit extends PureComponent { handleChange = value => { const { dispatch, form } = this.props; form.resetFields(['roleId', 'deptId']); - dispatch(USER_CHANGE_INIT({ tenantCode: value })); + dispatch(USER_CHANGE_INIT({ tenantId: value })); }; render() { @@ -113,14 +113,14 @@ class UserEdit extends PureComponent { - {getFieldDecorator('tenantCode', { + {getFieldDecorator('tenantId', { rules: [ { required: true, message: '请选择所属租户', }, ], - initialValue: detail.tenantCode, + initialValue: detail.tenantId, })(