提交 11976baad465bfda0443ef18784bfe5e9bd65a1e

作者 fanwh
1 个父辈 a54f882b

add template

正在显示 40 个修改的文件 包含 3047 行增加19 行删除
... ... @@ -2,5 +2,9 @@
2 2 "presets": [
3 3 "@babel/react",
4 4 "@babel/env"
  5 + ],
  6 + "plugins": [
  7 + "@babel/plugin-syntax-dynamic-import",
  8 + "@babel/plugin-proposal-class-properties"
5 9 ]
6 10 }
\ No newline at end of file
... ...
... ... @@ -23,7 +23,8 @@ module.exports = {
23 23 use: {
24 24 loader: "babel-loader",
25 25 options: {
26   - presets: ["@babel/env", "@babel/react"]
  26 + presets: ["@babel/env", "@babel/react"],
  27 + plugins: ["@babel/plugin-proposal-class-properties", "@babel/plugin-syntax-dynamic-import"]
27 28 }
28 29 }
29 30 }, {
... ... @@ -64,7 +65,8 @@ module.exports = {
64 65 ],
65 66 resolve: {
66 67 alias: {
67   - src: path.resolve(rootPath, 'src')
  68 + src: path.resolve(rootPath, 'src'),
  69 + antd: path.resolve(rootPath, 'node_modules', 'antd')
68 70 }
69 71 },
70 72 output: {
... ...
... ... @@ -9,26 +9,35 @@
9 9 "author": "",
10 10 "license": "ISC",
11 11 "dependencies": {
  12 + "antd": "^3.20.0",
12 13 "classnames": "^2.2.6",
13 14 "connected-react-router": "^6.5.0",
14 15 "es6-promise": "^4.2.8",
15 16 "history": "^4.9.0",
16 17 "isomorphic-fetch": "^2.2.1",
17 18 "localforage": "^1.7.3",
  19 + "moment": "^2.24.0",
  20 + "prop-types": "^15.7.2",
  21 + "rc-animate": "^2.8.3",
18 22 "react": "^16.8.6",
19 23 "react-dom": "^16.8.6",
20 24 "react-loadable": "^5.5.0",
21 25 "react-redux": "^7.1.0",
22 26 "react-router": "^5.0.1",
  27 + "reduce-reducers": "^1.0.4",
23 28 "redux": "^4.0.1",
24 29 "redux-form": "^8.2.4",
25 30 "redux-saga": "^1.0.5",
26   - "workai-express": "git+http://gitlab.workai.com.cn/fanwh/workai-express.git"
  31 + "regenerator-runtime": "^0.13.2",
  32 + "uuid": "^3.3.2",
  33 + "workai-express": "git+http://gitlab.workai.com.cn/fanwh/workai-express.git#aecbfb5"
27 34 },
28 35 "devDependencies": {
29 36 "@babel/cli": "^7.4.4",
30 37 "@babel/core": "^7.4.5",
31 38 "@babel/node": "^7.4.5",
  39 + "@babel/plugin-proposal-class-properties": "^7.5.0",
  40 + "@babel/plugin-syntax-dynamic-import": "^7.2.0",
32 41 "@babel/preset-env": "^7.4.5",
33 42 "@babel/preset-react": "^7.0.0",
34 43 "babel-loader": "^8.0.6",
... ...
... ... @@ -10,7 +10,7 @@ exports = module.exports = function () {
10 10 dir: path.join(serviceDir, 'server', 'views'),
11 11 engine: 'ejs',
12 12 publicPath: '/',
13   - staticServerPath: path.join(serviceDir, 'build'),
  13 + staticServerPath: path.join(serviceDir, 'static'),
14 14 cluster: false,
15 15 ssl: {
16 16 enabled: false,
... ...
1 1 /* eslint-disable no-var */
  2 +import path from 'path';
  3 +import workaiExpress from 'workai-express';
2 4 import webpack from 'webpack';
3 5 import webpackDevMiddleware from 'webpack-dev-middleware';
4 6 import webpackHotMiddleware from 'webpack-hot-middleware';
5 7 import config from '../configs/webpack.develop.config';
6   -var path = require('path');
7   -var workaiExpress = require('workai-express');
  8 +
8 9 var app = workaiExpress.app;
9 10 var IoC = workaiExpress.IoC;
10 11 var bootable = workaiExpress.bootable;
11 12 const compiler = webpack(config);
12 13
13   -IoC.use(IoC.dir(path.join(__dirname, 'boot')));
14   -app.use(webpackDevMiddleware(compiler, {
  14 +IoC.use(IoC.dir(path.join(__dirname, 'boot')));//加载配置文件
  15 +
  16 +app.use(webpackDevMiddleware(compiler, {//要在路有前加载webpack打包中间价
15 17 publicPath: config.output.publicPath
16 18 }));
17   -app.use(webpackHotMiddleware(compiler));
  19 +app.use(webpackHotMiddleware(compiler));//要在路有前加载webpack热加载中间价
18 20
  21 +app.phase(bootable.di.routes(path.join(__dirname, 'routes', 'index.js')));//载入路由
19 22
20   -app.phase(bootable.di.routes('./routes'));//载入路由
21 23
22   -app.boot(function (err) {
  24 +app.boot(function (err) {//配置插件加载完启动server
23 25 if (err) {
24 26 console.log(err);
25 27 process.exit(-1);
26 28 return;
27 29 }
28   -});
29   -
30   -
31   -
  30 +});
\ No newline at end of file
... ...
1 1
2 2 // app - routes
  3 +var path = require('path');
3 4 var workaiExpress = require('workai-express');
4 5 var IoC = workaiExpress.IoC;
5 6 var bootable = workaiExpress.bootable;
... ... @@ -8,7 +9,7 @@ exports = module.exports = function (settings) {
8 9
9 10 var app = this;
10 11 //auth
11   - app.phase(bootable.di.routes('./routes/login.js'));
  12 + app.phase(bootable.di.routes(path.join(__dirname, 'login.js')));
12 13
13 14 };
14 15
... ...
... ... @@ -8,8 +8,9 @@ exports = module.exports = function (settings, logger) {
8 8 router.get('/', function (req, res, next) {
9 9 res.render('index.html', { 'csrfToken': 'xxxx' });
10 10 });
11   - router.get('/login', function (req, res, next) {
12   - res.render('index.html', { 'csrfToken': 'xxxx' });
  11 + router.post('/login', function (req, res, next) {
  12 + logger.info(req.body);
  13 + res.send({ 'csrfToken': 'xxxx' });
13 14 });
14 15 app.use('/', router);
15 16 };
... ...
1 1 import React from 'react';
  2 +import { Provider } from "react-redux";
  3 +import store, { history } from './redux/store';
  4 +import AppRoutes from './routes';
2 5 import cx from 'classnames';
  6 +import 'antd/dist/antd.css';
  7 +import './less/app.less';
  8 +import zh_CN from 'antd/lib/locale-provider/zh_CN';
  9 +import { LocaleProvider } from 'antd';
3 10
4 11
5 12 class App extends React.Component {
... ... @@ -14,7 +21,12 @@ class App extends React.Component {
14 21 render() {
15 22 return (
16 23 <div className={cx('app_wrap')}>
17   - laxxxx
  24 + <LocaleProvider locale={zh_CN}>
  25 + <Provider store={store}>
  26 + <AppRoutes history={history}>
  27 + </AppRoutes>
  28 + </Provider>
  29 + </LocaleProvider>
18 30 </div>
19 31 );
20 32 }
... ...
  1 +import React from 'react';
  2 +import PropTypes from 'prop-types';
  3 +import { connect } from 'react-redux';
  4 +import { submit } from 'redux-form';
  5 +import { Menu, Icon } from 'antd';
  6 +import { pushRoute } from '../../utils/commonUtils';
  7 +import { changeSystemMenu } from '../../redux/actions/system';
  8 +import cx from 'classnames';
  9 +
  10 +const SubMenu = Menu.SubMenu;
  11 +const MenuItemGroup = Menu.ItemGroup;
  12 +
  13 +//格式化菜单
  14 +const formatMenu = (perms) => {
  15 + const menu1 = {}, menu2 = {}, menus = [];
  16 + if (perms) {
  17 + perms.map((perm, i) => {
  18 + if (!perm.parent_module) {
  19 + menu1[perm.module] = {
  20 + ...perm,
  21 + display_name: perm.module_name
  22 + };
  23 + } else {
  24 + if (menu2[perm.parent_module]) {
  25 + menu2[perm.parent_module].push({
  26 + ...perm,
  27 + display_name: perm.module_name
  28 + });
  29 + } else {
  30 + menu2[perm.parent_module] = [{
  31 + ...perm,
  32 + display_name: perm.module_name
  33 + }];
  34 + }
  35 + }
  36 + });
  37 + const keys = Object.keys(menu1);
  38 + keys.map((key, i) => {
  39 + if (menu2[key]) {
  40 + menus.push({
  41 + ...menu1[key],
  42 + children: menu2[key]
  43 + });
  44 + } else {
  45 + menus.push({
  46 + ...menu1[key]
  47 + });
  48 + }
  49 + });
  50 + }
  51 + return menus;
  52 +};
  53 +
  54 +
  55 +class SysMenu extends React.Component {
  56 + static propTypes = {
  57 + form: PropTypes.string,
  58 + onClick: PropTypes.func
  59 + }
  60 + static defaultProps = {
  61 + }
  62 + constructor(props) {
  63 + super(props);
  64 + this.handelClick = this.handelClick.bind(this);
  65 + this.renderSubMenu = this.renderSubMenu.bind(this);
  66 + this.handleClick = this.handleClick.bind(this);
  67 + this.handleOpenChange = this.handleOpenChange.bind(this);
  68 + }
  69 + componentDidMount() {
  70 + }
  71 + handelClick() {
  72 + const { onClick, form, dispatch } = this.props;
  73 + if (onClick) {
  74 + onClick();
  75 + } else {
  76 + dispatch(submit(form));
  77 + }
  78 + }
  79 + handleClick(modules) {
  80 + const { dispatch } = this.props;
  81 + const { keyPath, key } = modules;
  82 + const newOpenKeys = [].concat(keyPath);
  83 + if (newOpenKeys.length > 0)
  84 + newOpenKeys.shift();
  85 + dispatch(changeSystemMenu({
  86 + openKeys: newOpenKeys,
  87 + selectedKeys: [key]
  88 + }));
  89 + pushRoute(`main/${modules.key}`);
  90 + }
  91 + handleOpenChange(openKeys) {
  92 + const { selectedKeys, dispatch } = this.props;
  93 + dispatch(changeSystemMenu({
  94 + openKeys,
  95 + selectedKeys
  96 + }));
  97 + }
  98 + renderSubMenu(subMenus) {
  99 + return subMenus.map((subMenu, i) => {
  100 + return (
  101 + <Menu.Item key={subMenu.module}>
  102 + <span className="nav-text">{subMenu.display_name}{subMenu && subMenu.is_beta && subMenu.is_beta == 'y' && <span style={{ color: 'rgba(153, 169, 191,0.6)' }}> 试用 </span>}</span>
  103 + </Menu.Item>
  104 + );
  105 + });
  106 + }
  107 + render() {
  108 + const { uaa_perms, openKeys, selectedKeys } = this.props;
  109 + const menus = formatMenu(uaa_perms);
  110 + return (
  111 + <Menu className={cx('system_wrap')}
  112 + onClick={this.handleClick}
  113 + style={{ width: '100%' }}
  114 + onOpenChange={this.handleOpenChange}
  115 + selectedKeys={selectedKeys}
  116 + openKeys={openKeys}
  117 + mode="inline">
  118 + {menus && menus.map((menu, i) => {
  119 + if (menu.children) {
  120 + return (
  121 + <SubMenu key={menu.module} title={
  122 + <span><img style={{ width: '12px', marginRight: '8px', verticalAlign: 'baseline' }} src={'menuIconMap[menu.module]'} alt="" />{menu.display_name}</span>
  123 + }>
  124 + {this.renderSubMenu(menu.children)}
  125 + </SubMenu>
  126 + );
  127 + } else {
  128 + return (
  129 + <Menu.Item key={menu.module} >
  130 + <span className="nav-text">
  131 + <img style={{ width: '12px', marginRight: '8px', verticalAlign: 'baseline' }} src={'menuIconMap[menu.module]'} alt="" />
  132 + {menu.display_name}
  133 + {menu && menu.module && menu.module == 'persontax' && <span className={cx('menu_new')}></span>}
  134 + </span>
  135 + </Menu.Item>
  136 + );
  137 + }
  138 + })}
  139 + </Menu>
  140 + );
  141 + }
  142 +}
  143 +
  144 +
  145 +
  146 +const mapState = (state) => {
  147 + const {
  148 + router = {},
  149 + // system: { system_menu_selected_keys: { openKeys, selectedKeys } }
  150 + } = state;
  151 + return {
  152 + router,
  153 + uaa_tenant: {},
  154 + uaa_perms: [],
  155 + openKeys: [],
  156 + selectedKeys: []
  157 + };
  158 +};
  159 +export default connect(mapState)(SysMenu);
\ No newline at end of file
... ...
  1 +import React, { createElement } from 'react';
  2 +import { connect } from 'react-redux';
  3 +import PropTypes from 'prop-types';
  4 +import { Radio, Input, Select, Cascader, InputNumber, Checkbox, DatePicker, TimePicker, Icon, Progress, Modal } from 'antd';
  5 +import { Field, change, getFormValues, arrayPush, arrayRemove } from 'redux-form';
  6 +import Animate from 'rc-animate';
  7 +import moment from 'moment';
  8 +import './reduxForm.less';
  9 +import cx from 'classnames';
  10 +
  11 +const Option = Select.Option;
  12 +const RadioGroup = Radio.Group;
  13 +const CheckboxGroup = Checkbox.Group;
  14 +const { MonthPicker, RangePicker, WeekPicker } = DatePicker;
  15 +const { TextArea } = Input;
  16 +
  17 +function filter(inputValue, path) {
  18 + return (path.some(option => (option.label).toLowerCase().indexOf(inputValue.toLowerCase()) > -1));
  19 +}
  20 +
  21 +function getClassName(object, defaultName) {
  22 + const nameFromToStringRegex = /^function\s?([^\s(]*)/;
  23 + let result = "";
  24 + if (typeof object === 'function') {
  25 + result = object.name || object.toString().match(nameFromToStringRegex)[1];
  26 + } else if (typeof object.constructor === 'function') {
  27 + result = getClassName(object.constructor, defaultName);
  28 + }
  29 + return result || defaultName;
  30 +}
  31 +
  32 +function getDefaultMappingName(preName, name) {
  33 + if ((preName && preName.lastIndexOf(".") == -1) || name.indexOf(".") != -1) {
  34 + return name;
  35 + } else if (preName && preName.lastIndexOf(".") != -1 && name.indexOf(".") == -1) {
  36 + return preName.substring(0, preName.lastIndexOf(".") + 1) + name;
  37 + }
  38 +}
  39 +
  40 +
  41 +
  42 +export class ReduxFormArrayPush extends React.Component {
  43 + render() {
  44 + const { name, form, label, item = {} } = this.props;
  45 + return <a href={"javascript:;"} onClick={() => {
  46 +
  47 + }}> {label}</a>;
  48 + }
  49 +}
  50 +
  51 +export class ReduxFormArrayRemove extends React.Component {
  52 + render() {
  53 + const { index, name, form, className, firstRemove = false, title } = this.props;
  54 + if (index > 0 || firstRemove) {
  55 + return <Icon title={title} type="close" className={className} style={{ color: 'red' }} onClick={() => {
  56 +
  57 + }} />;
  58 + } else {
  59 + return null;
  60 + }
  61 + }
  62 +}
  63 +
  64 +class IfEles extends React.Component {
  65 + static propTypes = {
  66 + allValues: PropTypes.object,
  67 + form: PropTypes.string,
  68 + // showFun: PropTypes.fun,
  69 + name: PropTypes.string
  70 + }
  71 + static defaultProps = {
  72 + showValue: '160'
  73 + }
  74 + constructor(props) {
  75 + super(props);
  76 + this.showHideFun = this.showHideFun.bind(this);
  77 + }
  78 + componentDidMount() {
  79 + }
  80 + showHideFun() {
  81 + const { allValues = {}, name = '', showFun, showValue } = this.props;
  82 + let flag = false;
  83 +
  84 + return flag;
  85 + }
  86 + render() {
  87 + const { className } = this.props;
  88 + const showFlag = this.showHideFun();
  89 + return showFlag
  90 + ? <div style={{ ...this.props.style }} className={cx('form_field_if_else_wrap', className)}>
  91 + {this.props.children}
  92 + </div> :
  93 + null;
  94 + }
  95 +}
  96 +const mapState = (state, props) => {
  97 + const { form } = props;
  98 + return {
  99 + allValues: getFormValues(form)(state)
  100 + };
  101 +};
  102 +export class IfElesWrap extends React.Component {
  103 + static propTypes = {
  104 + form: PropTypes.string,
  105 + // showFun: PropTypes.fun,
  106 + name: PropTypes.string
  107 + }
  108 + static defaultProps = {
  109 + showValue: '160'
  110 + }
  111 + constructor(props) {
  112 + super(props);
  113 + this.state = {
  114 + component: null
  115 + };
  116 + }
  117 + componentDidMount() {
  118 + let MyFormWrap = connect(mapState)(IfEles);
  119 + this.setState({
  120 + component: MyFormWrap
  121 + });
  122 + }
  123 + UNSAFE_componentWillReceiveProps(nextProps) {
  124 + const C = this.state.component;
  125 + if (!C) {
  126 + let MyFormWrap = connect(mapState)(IfEles);
  127 + this.setState({
  128 + component: MyFormWrap
  129 + });
  130 + }
  131 + }
  132 + render() {
  133 + const C = this.state.component;
  134 + return C
  135 + ? <C {...this.props}>
  136 + {this.props.children}
  137 + </C >
  138 + : null;
  139 + }
  140 +}
  141 +
  142 +
  143 +class ImgShowUI extends React.Component {
  144 + static propTypes = {
  145 + filemeta: PropTypes.object
  146 + }
  147 + static defaultProps = {
  148 + preview: true,
  149 + removeImg: (file) => {
  150 +
  151 + }
  152 + }
  153 + constructor(props) {
  154 + super(props);
  155 + this.state = {
  156 + url: '',
  157 + previewVisible: false
  158 + };
  159 + }
  160 + componentDidMount() {
  161 + const { filemeta } = this.props, self = this;
  162 +
  163 + }
  164 + UNSAFE_componentWillReceiveProps(nextProps) {
  165 + const { filemeta } = nextProps, self = this;
  166 + const preProps = this.props;
  167 +
  168 + }
  169 + render() {
  170 + const { url, previewVisible } = this.state;
  171 + const { filemeta } = this.props;
  172 + const isImg = (imgType) => {
  173 + if (imgType == "image/jpeg" || "image/png" == imgType) {
  174 + return true;
  175 + } else {
  176 + return false;
  177 + }
  178 + };
  179 + return (
  180 + <div style={{ ...this.props.style }} className={cx('input_file_shows_item_img')}>
  181 + <Modal visible={previewVisible} footer={null} onCancel={() => {
  182 + this.setState({ previewVisible: false });
  183 + }}>
  184 + <img alt="example" style={{ width: '100%' }} src={url} />
  185 + </Modal>
  186 + <div className={cx('input_file_shows_item_mask')}>
  187 + <span className={cx('input_file_shows_item_actions')}>
  188 + {!isImg(filemeta.type) && <Icon type="download" title="下载" />}
  189 + {isImg(filemeta.type) && <Icon type="eye" title="查看" onClick={() => {
  190 + this.setState({ previewVisible: true });
  191 + }} />}
  192 + <Icon type="delete" title="删除" onClick={() => {
  193 + this.props.removeImg(filemeta);
  194 + }} />
  195 + </span>
  196 + </div>
  197 + <img src={url} alt="" />
  198 + </div>
  199 + );
  200 + }
  201 +}
  202 +
  203 +
  204 +class InputFieldUI extends React.Component {
  205 + static propTypes = {
  206 + name: PropTypes.string,
  207 + placeholder: PropTypes.string,
  208 + validate: PropTypes.array,
  209 + options: PropTypes.array,
  210 + optionKey: PropTypes.string,
  211 + optionValue: PropTypes.string,
  212 + optionStyle: PropTypes.object
  213 + }
  214 + static defaultProps = {
  215 + lableAlign: 'right', //left|right|center
  216 + labelWidth: '160', //auto|160|formItemLayout
  217 + width: '270', //auto|270|formItemLayout
  218 + layout: 'block', //'horizontal'|'vertical'|'inline'|'block'
  219 + showTime: false,
  220 + unix: true,
  221 + placeholder: "",
  222 + prefix: null,
  223 + format: "HH:mm",
  224 + formatDate: "YYYY/MM/DD",
  225 + formatMonth: "YYYY/MM",
  226 + validate: [],
  227 + rows: 6,
  228 + options: [],
  229 + optionKey: 'id',
  230 + optionValue: 'name',
  231 + optionStyle: { 'display': 'inline-block' },
  232 + showSearch: true,
  233 + allowClear: true,
  234 + dropdownMatchSelectWidth: true,
  235 + province_code: "province_code",
  236 + city_code: "city_code",
  237 + district_code: "district_code",
  238 + province: "province",
  239 + city: "city",
  240 + district: "district"
  241 + }
  242 + static getDerivedStateFromProps(nextProps, prevState) {
  243 + const { field, form, province_code, city_code, district_code, type, name } = nextProps;
  244 + const { pristine } = field.meta;
  245 + switch (type) {
  246 + case 'area':
  247 + return null;
  248 + default:
  249 + return null;
  250 + }
  251 + }
  252 + constructor(props) {
  253 + super(props);
  254 + this.validateStatus = this.validateStatus.bind(this);
  255 + this.showErrMessage = this.showErrMessage.bind(this);
  256 + this.renderField = this.renderField.bind(this);
  257 + this.renderLabel = this.renderLabel.bind(this);
  258 + this.onHelpAnimEnd = this.onHelpAnimEnd.bind(this);
  259 + this.loadOptions = this.loadOptions.bind(this);
  260 + // this.updateFieldRender = this.updateFieldRender.bind(this);
  261 + this.formatValueForTime = this.formatValueForTime.bind(this);
  262 + this.formatValueForDate = this.formatValueForDate.bind(this);
  263 + this.formatValueForMonth = this.formatValueForMonth.bind(this);
  264 + this.formatValueForMonthRange = this.formatValueForMonthRange.bind(this);
  265 + this.formatValueForDateRange = this.formatValueForDateRange.bind(this);
  266 + // this.extChangeAction = this.extChangeAction.bind(this);
  267 + // this.extDisabled = this.extDisabled.bind(this);
  268 + this.state = {
  269 + monthrange: ['date', 'date'],
  270 + reload: false,
  271 + files: [],
  272 + fileRef: 'file' + new Date().getTime()
  273 + };
  274 + this.helpShow = false;
  275 + }
  276 + formatValueForTime(field) {
  277 + const { format } = this.props;
  278 + let value = null;
  279 + if (field.input.value && this.props.unix) {
  280 + value = moment(field.input.value * 1000);
  281 + } else if (field.input.value) {
  282 + value = moment(field.input.value, this.props.format ? format : 'HH:mm');
  283 + }
  284 + return value;
  285 + }
  286 + formatValueForDate(field) {
  287 + const { formatDate } = this.props;
  288 + let value = null;
  289 + if (field.input.value && this.props.unix) {
  290 + value = moment(field.input.value * 1000);
  291 + } else if (field.input.value) {
  292 + value = moment(field.input.value, this.props.showTime ? formatDate + ' HH:mm' : formatDate);
  293 + }
  294 + return value;
  295 + }
  296 + formatValueForMonth(field) {
  297 + const { formatMonth } = this.props;
  298 + let value = null;
  299 + if (field.input.value && this.props.unix) {
  300 + value = moment(field.input.value * 1000);
  301 + } else if (field.input.value) {
  302 + value = moment(field.input.value, formatMonth);
  303 + }
  304 + return value;
  305 + }
  306 + formatValueForMonthRange(field) {
  307 + const { formatMonth } = this.props;
  308 + let values = null;
  309 + if (field.input.value && field.input.value[0] && field.input.value[1] && this.props.unix) {
  310 + values = [moment(field.input.value[0] * 1000), moment(field.input.value[1] * 1000)];
  311 + } else if (field.input.value) {
  312 + values = [moment(field.input.value[0] * 1000, formatMonth), moment(field.input.value[1] * 1000, formatMonth)];
  313 + }
  314 + return values;
  315 + }
  316 + formatValueForDateRange(field) {
  317 + const { formatDate } = this.props;
  318 + let values = null;
  319 + if (field.input.value && field.input.value[0] && field.input.value[1] && this.props.unix) {
  320 + values = [moment(field.input.value[0] * 1000), moment(field.input.value[1] * 1000)];
  321 + } else if (field.input.value) {
  322 + values = [moment(field.input.value[0] * 1000, this.props.showTime ? formatDate + ' HH:mm' : formatDate), moment(field.input.value[1] * 1000, this.props.showTime ? formatDate + ' HH:mm' : formatDate)];
  323 + }
  324 + return values;
  325 + }
  326 + validateStatus() {
  327 + const { field } = this.props;
  328 + if (field && field.meta && field.meta.touched && field.meta.error) {
  329 + return true;
  330 + } else {
  331 + return false;
  332 + }
  333 + }
  334 + showErrMessage(field) {
  335 + if (field && field.meta && field.meta.touched && field.meta.error) {
  336 + return field.meta.error;
  337 + } else {
  338 + return '';
  339 + }
  340 + }
  341 + onHelpAnimEnd(_key, helpShow) {
  342 + this.helpShow = helpShow;
  343 + if (!helpShow) {
  344 + this.setState({
  345 + reload: !this.state.reload
  346 + });
  347 + }
  348 + }
  349 + renderHelp(field) {
  350 + const help = this.showErrMessage(field);
  351 + const children = help ? (
  352 + <div className={cx('form_field_explain')} key="help">
  353 + {help}
  354 + </div>
  355 + ) : null;
  356 + if (children) {
  357 + this.helpShow = !!children;
  358 + }
  359 + return (
  360 + <Animate
  361 + transitionName="show-help"
  362 + component=""
  363 + transitionAppear
  364 + key="help"
  365 + onEnd={this.onHelpAnimEnd}>
  366 + {children}
  367 + </Animate>
  368 + );
  369 + }
  370 + loadOptions() {
  371 + const { options = [], optionsAjax, form, name, stateName } = this.props;
  372 + if (optionsAjax) {
  373 + return '';
  374 + } else {
  375 + return options;
  376 + }
  377 + }
  378 + renderRadiogroup() {
  379 + const { name, placeholder, width, disabled, field,
  380 + optionKey, optionValue, optionStyle } = this.props;
  381 + this.helpShow = !!this.validateStatus();
  382 + const styleWidth = width == 'auto' ? { width: '100%' } : { width: `${width}px` };
  383 + const options = this.loadOptions();
  384 + return (
  385 + <div className={cx('form_field_item_control', this.validateStatus() ? 'has_error' : null)} style={{ ...styleWidth }}>
  386 + <RadioGroup {...field.input} className={cx('form_field_input_radio_group', 'form_field_input', this.props.className)} disabled={disabled} placeholder={placeholder} name={name}
  387 + style={{ width: '100%' }} onChange={(value) => {
  388 + if (this.props.onChange) {
  389 + this.props.onChange(value, field);
  390 + } else {
  391 + field.input.onChange(value);
  392 + }
  393 + }}>
  394 + {options && options.length > 0 && options.map((option, i) => {
  395 + return (
  396 + <Radio {...option} key={i} value={option[optionKey]} style={{ ...optionStyle }}>{option[optionValue]}</Radio>
  397 + );
  398 + })}
  399 + </RadioGroup>
  400 + {this.renderHelp(field)}
  401 + </div>
  402 + );
  403 + }
  404 + renderCheckboxgroup() {
  405 + const { name, placeholder, width, disabled, field,
  406 + optionKey, optionValue, optionStyle } = this.props;
  407 + this.helpShow = !!this.validateStatus();
  408 + const styleWidth = width == 'auto' ? { width: '100%' } : { width: `${width}px` };
  409 + const options = this.loadOptions();
  410 + return (
  411 + <div className={cx('form_field_item_control', this.validateStatus() ? 'has_error' : null)} style={{ ...styleWidth }}>
  412 + <CheckboxGroup className={cx('form_field_input_checkbox_group', 'form_field_input', this.props.className)} disabled={disabled} placeholder={placeholder} name={name}
  413 + onChange={
  414 + (value) => {
  415 + if (this.props.onChange) {
  416 + this.props.onChange(value, field);
  417 + } else {
  418 + if (value.length == 0) {
  419 + field.input.onChange(null);
  420 + } else
  421 + field.input.onChange(value);
  422 + }
  423 + }
  424 + } value={field.input.value ? field.input.value : null}>
  425 + {options && options.length > 0 && options.map((option, i) => {
  426 + return (
  427 + <Checkbox key={i} value={option[optionKey]} style={{ ...optionStyle }}>{option[optionValue]}</Checkbox>
  428 + );
  429 + })}
  430 + </CheckboxGroup>
  431 + {this.renderHelp(field)}
  432 + </div>
  433 + );
  434 + }
  435 + renderText() {
  436 + const { name, placeholder, width, disabled, prefix, field } = this.props;
  437 + this.helpShow = !!this.validateStatus();
  438 + const styleWidth = width == 'auto' ? { width: '100%' } : { width: `${width}px` };
  439 + return (
  440 + <div className={cx('form_field_item_control', this.validateStatus() ? 'has_error' : null)} style={{ ...styleWidth }}>
  441 + <Input {...field.input} className={cx('form_field_input_text', 'form_field_input', this.props.className)} disabled={disabled} placeholder={placeholder} name={name}
  442 + style={{ width: '100%' }} onChange={(value) => {
  443 + if (this.props.onChange) {
  444 + this.props.onChange(value, field);
  445 + } else {
  446 + field.input.onChange(value);
  447 + }
  448 + }} prefix={prefix} />
  449 + {this.renderHelp(field)}
  450 + </div >
  451 + );
  452 + }
  453 + renderTextarea() {
  454 + const { name, placeholder, width, disabled, prefix, field, rows } = this.props;
  455 + this.helpShow = !!this.validateStatus();
  456 + const styleWidth = width == 'auto' ? { width: '100%' } : { width: `${width}px` };
  457 + return (
  458 + <div className={cx('form_field_item_control', this.validateStatus() ? 'has_error' : null)} style={{ ...styleWidth }}>
  459 + <TextArea rows={rows} {...field.input} className={cx('form_field_input_textarea', 'form_field_input', this.props.className)} disabled={disabled} placeholder={placeholder}
  460 + name={name} style={{ width: '100%' }}
  461 + onChange={(value) => {
  462 + if (this.props.onChange) {
  463 + this.props.onChange(value, field);
  464 + } else {
  465 + field.input.onChange(value);
  466 + }
  467 + }} prefix={prefix} />
  468 + {this.renderHelp(field)}
  469 + </div >
  470 + );
  471 + }
  472 + renderSelect() {
  473 + const { name, placeholder, width, disabled, prefix, field, showSearch, allowClear, dropdownMatchSelectWidth, optionKey, optionValue } = this.props;
  474 + this.helpShow = !!this.validateStatus();
  475 + const styleWidth = width == 'auto' ? { width: '100%' } : { width: `${width}px` };
  476 + const options = this.loadOptions();
  477 + return (
  478 + <div className={cx('form_field_item_control', this.validateStatus() ? 'has_error' : null)} style={{ ...styleWidth }}>
  479 + <Select {...field.input} className={cx('form_field_input_select', 'form_field_input', this.props.className)} disabled={disabled} placeholder={placeholder} name={name}
  480 + style={{ width: '100%' }} getPopupContainer={(triggerNode) => { return triggerNode; }} filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
  481 + allowClear={allowClear} showSearch={showSearch} onSelect={this.props.onSelect} dropdownMatchSelectWidth={dropdownMatchSelectWidth} notFoundContent={'无数据'}
  482 + onChange={(value) => {
  483 + if (this.props.onChange) {
  484 + if (!value) {
  485 + this.props.onChange('', field);
  486 + } else {
  487 + this.props.onChange(value, field);
  488 + }
  489 + } else {
  490 + if (!value)
  491 + if (value == 0) {
  492 + field.input.onChange('0');
  493 + } else {
  494 + field.input.onChange('');
  495 + }
  496 + else
  497 + field.input.onChange(value);
  498 + }
  499 + }} prefix={prefix}>
  500 + {options && options.length > 0 && options.map((option, i) => {
  501 + return (
  502 + <Option {...option} key={i} value={option[optionKey]}>{option[optionValue]}</Option>
  503 + );
  504 + })}
  505 + </Select>
  506 + {this.renderHelp(field)}
  507 + </div >
  508 + );
  509 + }
  510 + renderCascader() {
  511 + const { name, placeholder, width, disabled, prefix, field } = this.props;
  512 + this.helpShow = !!this.validateStatus();
  513 + const styleWidth = width == 'auto' ? { width: '100%' } : { width: `${width}px` };
  514 + const options = this.loadOptions();
  515 + return (
  516 + <div className={cx('form_field_item_control', this.validateStatus() ? 'has_error' : null)} style={{ ...styleWidth }}>
  517 + <Cascader {...field.input} className={cx('form_field_input_cascader', 'form_field_input', this.props.className)} disabled={disabled} options={options} placeholder={placeholder}
  518 + name={name} getPopupContainer={(triggerNode) => { return triggerNode; }} style={{ width: '100%' }} filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
  519 + onChange={(value) => {
  520 + if (this.props.onChange) {
  521 + this.props.onChange(value, field);
  522 + } else {
  523 + field.input.onChange(value);
  524 + }
  525 + }} prefix={prefix} />
  526 + {this.renderHelp(field)}
  527 + </div >
  528 + );
  529 + }
  530 + renderNumber() {
  531 + const { name, placeholder, width, disabled, prefix, field } = this.props;
  532 + this.helpShow = !!this.validateStatus();
  533 + const styleWidth = width == 'auto' ? { width: '100%' } : { width: `${width}px` };
  534 + return (
  535 + <div className={cx('form_field_item_control', this.validateStatus() ? 'has_error' : null)} style={{ ...styleWidth }}>
  536 + <InputNumber {...field.input} className={cx('form_field_input_number', 'form_field_input', this.props.className)} disabled={disabled} placeholder={placeholder} name={name}
  537 + style={{ width: '100%' }} onChange={(value) => {
  538 + if (this.props.onChange) {
  539 + this.props.onChange(value, field);
  540 + } else {
  541 + field.input.onChange(value);
  542 + }
  543 + }}
  544 + onBlur={(value) => {
  545 + if (this.props.onBlur) {
  546 + this.props.onBlur(value, field);
  547 + } else {
  548 + field.input.onBlur(value);
  549 + }
  550 + }} prefix={prefix} />
  551 + {this.renderHelp(field)}
  552 + </div >
  553 + );
  554 + }
  555 + renderCheckbox() {
  556 + const { name, placeholder, width, disabled, prefix, field } = this.props;
  557 + this.helpShow = !!this.validateStatus();
  558 + const styleWidth = width == 'auto' ? { width: '100%' } : { width: `${width}px` };
  559 + return (
  560 + <div className={cx('form_field_item_control', this.validateStatus() ? 'has_error' : null)} style={{ ...styleWidth }}>
  561 + <Checkbox className={cx('form_field_input_checkbox', 'form_field_input', this.props.className)} disabled={disabled} placeholder={placeholder} name={name} onChange={
  562 + (value) => {
  563 + if (this.props.onChange) {
  564 + this.props.onChange(value.target.checked ? 'y' : '', field);
  565 + } else {
  566 + field.input.onChange(value.target.checked ? 'y' : '');
  567 + }
  568 + }
  569 + }
  570 + checked={field.input.value ? field.input.value == 'y' : false} prefix={prefix} >
  571 + {this.props.label}
  572 + </Checkbox>
  573 + {this.renderHelp(field)}
  574 + </div >
  575 + );
  576 + }
  577 + renderDate() {
  578 + const { name, placeholder, width, disabled, field, formatDate, showTime } = this.props;
  579 + this.helpShow = !!this.validateStatus();
  580 + const styleWidth = width == 'auto' ? { width: '100%' } : { width: `${width}px` };
  581 + return (
  582 + <div className={cx('form_field_item_control', this.validateStatus() ? 'has_error' : null)} style={{ ...styleWidth }}>
  583 + <DatePicker className={cx('form_field_input_datepicker', 'form_field_input', this.props.className)} disabled={disabled} placeholder={placeholder} name={name} style={{ width: '100%' }}
  584 + format={this.props.showTime ? formatDate + ' HH:mm' : formatDate} getCalendarContainer={(trigger) => {
  585 + return trigger;
  586 + }} showTime={showTime} onChange={(time, timeString) => {
  587 + let value = null;
  588 + if (this.props.unix && time) {
  589 + value = time.unix();
  590 + } else if (time) {
  591 + value = time.format(this.props.showTime ? formatDate + ' HH:mm' : formatDate);
  592 + }
  593 + if (this.props.onChange) {
  594 + this.props.onChange(value, field);
  595 + } else {
  596 + field.input.onChange(value);
  597 + }
  598 + }} value={this.formatValueForDate(field)} />
  599 + {this.renderHelp(field)}
  600 + </div >
  601 + );
  602 + }
  603 + renderMonth() {
  604 + const { name, placeholder, width, disabled, field, formatMonth } = this.props;
  605 + this.helpShow = !!this.validateStatus();
  606 + const styleWidth = width == 'auto' ? { width: '100%' } : { width: `${width}px` };
  607 + return (
  608 + <div className={cx('form_field_item_control', this.validateStatus() ? 'has_error' : null)} style={{ ...styleWidth }}>
  609 + <MonthPicker className={cx('form_field_input_monthpicker', 'form_field_input', this.props.className)} disabled={disabled} placeholder={placeholder} name={name} style={{ width: '100%' }}
  610 + format={formatMonth} getCalendarContainer={(trigger) => { return trigger; }} onChange={(time, timeString) => {
  611 + let value = null;
  612 + if (this.props.unix && time) {
  613 + value = time.unix();
  614 + } else if (time) {
  615 + value = time.format(formatMonth);
  616 + }
  617 + if (this.props.onChange) {
  618 + this.props.onChange(value, field);
  619 + } else {
  620 + field.input.onChange(value);
  621 + }
  622 + }} value={this.formatValueForMonth(field)} />
  623 + {this.renderHelp(field)}
  624 + </div >
  625 + );
  626 + }
  627 + renderDaterange() {
  628 + const { name, placeholder, width, disabled, field, formatDate, formatMonth, showTime } = this.props;
  629 + this.helpShow = !!this.validateStatus();
  630 + const styleWidth = width == 'auto' ? { width: '100%' } : { width: `${width}px` };
  631 + return (
  632 + <div className={cx('form_field_item_control', this.validateStatus() ? 'has_error' : null)} style={{ ...styleWidth }}>
  633 + <RangePicker className={cx('form_field_input_daterange', 'form_field_input', this.props.className)} disabled={disabled} placeholder={placeholder} name={name} style={{ width: '100%' }}
  634 + ranges={{ '今天': [moment(), moment()], '本月': [moment().startOf('month'), moment().endOf('month')] }}
  635 + format={formatDate} getCalendarContainer={(trigger) => { return trigger; }} showTime={showTime} onChange={(times = [], timeStrings = []) => {
  636 + let values = null;
  637 + if (this.props.unix && times.length > 0 && times[0] && times[1]) {
  638 + values = [times[0].unix(), times[1].unix()];
  639 + } else if (times.length > 0 && times[0] && times[1]) {
  640 + values = [times[0].format(formatMonth), times[1].format(formatMonth)];
  641 + }
  642 + if (this.props.onChange) {
  643 + this.props.onChange(values, field);
  644 + } else {
  645 + field.input.onChange(values);
  646 + }
  647 + }} value={this.formatValueForDateRange(field)} />
  648 + {this.renderHelp(field)}
  649 + </div >
  650 + );
  651 + }
  652 + renderMonthrange() {
  653 + const { name, placeholder, width, disabled, field, formatMonth } = this.props;
  654 + this.helpShow = !!this.validateStatus();
  655 + const styleWidth = width == 'auto' ? { width: '100%' } : { width: `${width}px` };
  656 + return (
  657 + <div className={cx('form_field_item_control', this.validateStatus() ? 'has_error' : null)} style={{ ...styleWidth }}>
  658 + <RangePicker className={cx('form_field_input_monthrange', 'form_field_input', this.props.className)} disabled={disabled} placeholder={placeholder} name={name} style={{ width: '100%' }}
  659 + ranges={{ '本月': [moment().startOf('month'), moment().endOf('month')] }}
  660 + mode={['month', 'month']} format={formatMonth} getCalendarContainer={(trigger) => { return trigger; }} onChange={(times = [], timeStrings = []) => {
  661 + let values = null;
  662 + if (this.props.unix && times.length > 0 && times[0] && times[1]) {
  663 + values = [times[0].unix(), times[1].unix()];
  664 + } else if (times.length > 0 && times[0] && times[1]) {
  665 + values = [times[0].format(formatMonth), times[1].format(formatMonth)];
  666 + }
  667 + if (this.props.onChange) {
  668 + this.props.onChange(values, field);
  669 + } else {
  670 + field.input.onChange(values);
  671 + }
  672 + }} value={this.formatValueForMonthRange(field)}
  673 + onPanelChange={(times, mode) => {
  674 + let values = null;
  675 + if (this.props.unix && times.length > 0 && times[0] && times[1]) {
  676 + values = [times[0].unix(), times[1].unix()];
  677 + } else if (times.length > 0 && times[0] && times[1]) {
  678 + values = [times[0].format(formatMonth), times[1].format(formatMonth)];
  679 + }
  680 + if (this.props.onChange) {
  681 + this.props.onChange(values, field);
  682 + } else {
  683 + field.input.onChange(values);
  684 + }
  685 + }} />
  686 + {this.renderHelp(field)}
  687 + </div >
  688 + );
  689 + }
  690 + renderTime() {
  691 + const { name, placeholder, width, disabled, field, format } = this.props;
  692 + this.helpShow = !!this.validateStatus();
  693 + const styleWidth = width == 'auto' ? { width: '100%' } : { width: `${width}px` };
  694 + return (
  695 + <div className={cx('form_field_item_control', this.validateStatus() ? 'has_error' : null)} style={{ ...styleWidth }}>
  696 + <TimePicker className={cx('form_field_input_time', 'form_field_input', this.props.className)} disabled={disabled} placeholder={placeholder} name={name} style={{ width: '100%' }}
  697 + format={format ? format : 'HH:mm'} getPopupContainer={(trigger) => {
  698 + return trigger;
  699 + }} onChange={(time, timeString) => {
  700 + let value = null;
  701 + if (this.props.unix && time) {
  702 + value = time.unix();
  703 + } else if (time) {
  704 + value = time.format(format ? format : 'HH:mm');
  705 + }
  706 + if (this.props.onChange) {
  707 + this.props.onChange(value, field);
  708 + } else {
  709 + field.input.onChange(value);
  710 + }
  711 + }} value={this.formatValueForTime(field)} />
  712 + {this.renderHelp(field)}
  713 + </div >
  714 + );
  715 + }
  716 + renderField() {
  717 + const { type } = this.props;
  718 + switch (type) {
  719 + case 'radiogroup':
  720 + return this.renderRadiogroup();
  721 + case 'checkboxgroup':
  722 + return this.renderCheckboxgroup();
  723 + case 'text':
  724 + return this.renderText();
  725 + case 'textarea':
  726 + return this.renderTextarea();
  727 + case 'select':
  728 + return this.renderSelect();
  729 + case 'cascader':
  730 + return this.renderCascader();
  731 + case 'number':
  732 + return this.renderNumber();
  733 + case 'checkbox':
  734 + return this.renderCheckbox();
  735 + case 'date':
  736 + return this.renderDate();
  737 + case 'month':
  738 + return this.renderMonth();
  739 + case 'daterange':
  740 + return this.renderDaterange();
  741 + case 'monthrange':
  742 + return this.renderMonthrange();
  743 + case 'time':
  744 + return this.renderTime();
  745 + default:
  746 + return this.renderText();
  747 + }
  748 + }
  749 + renderLabel() {
  750 + const { label, labelWidth, showLabelText, lableAlign, type, validate } = this.props;
  751 + let is_required = false;
  752 + if (validate && validate.length > 0) {
  753 + validate.map((vali, i) => {
  754 + if ('checkbox' != type && 'required' == getClassName(vali)) {
  755 + is_required = true;
  756 + }
  757 + });
  758 + }
  759 + return (
  760 + <div className={cx('form_field_label', `form_field_label_${lableAlign}`, !showLabelText ? 'form_field_hidden_text' : null, 'checkbox' == type ? 'form_field_checkbox_hidden_text' : null)} >
  761 + <label title={label} className={cx({ 'ant-form-item-required': is_required })} style={{ width: labelWidth == 'auto' ? labelWidth : `${labelWidth - 8}px` }}>
  762 + {'checkbox' != type && label}
  763 + </label>
  764 + </div>
  765 + );
  766 + }
  767 + render() {
  768 + const { label } = this.props;
  769 + return (
  770 + <div className={cx('form_field_item_wrap', this.validateStatus() ? 'form_field_item_with_help' : null)}>
  771 + {label && this.renderLabel()}
  772 + {this.renderField()}
  773 + {this.props.children}
  774 + </div>
  775 + );
  776 + }
  777 +}
  778 +
  779 +class InputField extends React.Component {
  780 + constructor(props) {
  781 + super(props);
  782 + this.renderFormItem = this.renderFormItem.bind(this);
  783 + }
  784 + componentDidMount() {
  785 + }
  786 + renderFormItem(field) {
  787 + return createElement(InputFieldUI, { ...this.props, field });
  788 + }
  789 + render() {
  790 + const { validate, name, layout } = this.props;
  791 + let style = { display: 'block' };
  792 + if ('block' == layout) {
  793 + style = { display: 'block' };
  794 + } else if ('inline' == layout) {
  795 + style = { display: 'inline-block' };
  796 + }
  797 + return (
  798 + <div style={{ ...this.props.style, ...style }} className={cx('form_field_wrap')}>
  799 + <Field name={name} fieldId={'nexField' + name} component={this.renderFormItem} validate={validate}> </Field>
  800 + </div>
  801 + );
  802 + }
  803 +}
  804 +
  805 +
  806 +export default InputField;
\ No newline at end of file
... ...
  1 +import React from 'react';
  2 +import PropTypes from 'prop-types';
  3 +import { reduxForm } from 'redux-form';
  4 +import cx from 'classnames';
  5 +
  6 +
  7 +class FormWrap extends React.Component {
  8 + static propTypes = {
  9 + }
  10 + constructor(props) {
  11 + super(props);
  12 + }
  13 + componentDidMount() {
  14 + }
  15 + UNSAFE_componentWillReceiveProps(nextProps) {
  16 + }
  17 + componentWillUnmount() {
  18 + }
  19 + render() {
  20 + const { className } = this.props;
  21 + return (
  22 + <div className={cx('redux_form_wrap', className)}>
  23 + {this.props.children}
  24 + </div>
  25 + );
  26 + }
  27 +}
  28 +
  29 +
  30 +class ReduxFormWrap extends React.Component {
  31 + static propTypes = {
  32 + form: PropTypes.string,
  33 + onSubmit: PropTypes.func,
  34 + initialValues: PropTypes.object
  35 + }
  36 + static defaultProps = {
  37 + form: '@@redux-form-wrap',
  38 + onSubmit: (values) => { },
  39 + initialValues: {}
  40 + }
  41 + constructor(props) {
  42 + super(props);
  43 + this.state = {
  44 + component: null
  45 + };
  46 + }
  47 + componentDidMount() {
  48 + let MyFormWrap = reduxForm(this.props)(FormWrap);
  49 + this.setState({
  50 + component: MyFormWrap
  51 + });
  52 + }
  53 + UNSAFE_componentWillReceiveProps(nextProps) {
  54 + const C = this.state.component;
  55 + if (!C) {
  56 + let MyFormWrap = reduxForm(nextProps)(FormWrap);
  57 + this.setState({
  58 + component: MyFormWrap
  59 + });
  60 + }
  61 + }
  62 + render() {
  63 + const C = this.state.component;
  64 + const extInitialValues = {
  65 + ...this.props.initialValues, '__form_name': this.props.form
  66 + };
  67 + return C
  68 + ? <C {...this.props} initialValues={extInitialValues}>
  69 + {this.props.children}
  70 + </C >
  71 + : null;
  72 + }
  73 +
  74 +}
  75 +
  76 +export default ReduxFormWrap;
\ No newline at end of file
... ...
  1 +.form_field_wrap{
  2 + position: relative;
  3 + .ant-input-affix-wrapper{
  4 + .ant-input{
  5 + z-index: 1;
  6 + background: #fff;
  7 + }
  8 + }
  9 + .form_field_item_wrap{
  10 + // margin-bottom: 26px;
  11 + min-height: 58px;
  12 + display: flex;
  13 + }
  14 + .form_field_item_wrap.form_field_item_with_help{
  15 + // margin-bottom: 5px;
  16 + }
  17 + .form_field_item_with_help{
  18 + color: rgba(0,0,0,0.45);
  19 + line-height: 1.5;
  20 + -webkit-transition: color .3s cubic-bezier(.215, .61, .355, 1);
  21 + transition: color .3s cubic-bezier(.215, .61, .355, 1);
  22 + clear: both;
  23 + }
  24 + .form_field_input_radio_group{
  25 + border:1px solid transparent;
  26 + padding:8px;
  27 + border-radius: 4px;
  28 + }
  29 + .form_field_input_checkbox,.form_field_input_checkbox_group{
  30 + padding: 4px 8px;
  31 + border: 1px solid transparent;
  32 + }
  33 + .has_error{
  34 + .form_field_input_checkbox,.form_field_input_checkbox_group{
  35 + border: 1px solid #f5222d;
  36 + border-radius: 4px;
  37 + }
  38 + .form_field_explain {
  39 + color: #f5222d;
  40 + }
  41 + .form_field_input{
  42 + border-color: #f5222d;
  43 + input{
  44 + border-color: #f5222d;
  45 + }
  46 + input:focus{
  47 + border-color: #f5222d;
  48 + outline: 0;
  49 + -webkit-box-shadow: 0 0 0 2px rgba(245,34,45,0.2);
  50 + box-shadow: 0 0 0 2px rgba(245,34,45,0.2);
  51 + border-right-width: 1px !important;
  52 + }
  53 + .ant-calendar-input-wrap,.ant-time-picker-panel-input-wrap{
  54 + input{
  55 + border-color:transparent;
  56 + }
  57 + input:focus{
  58 + border-color:transparent;
  59 + -webkit-box-shadow: 0 0 0 2px rgba(245,34,45,0);
  60 + box-shadow: 0 0 0 2px rgba(245,34,45,0);
  61 + }
  62 + }
  63 + input.ant-calendar-range-picker-input:focus{
  64 + border-color:transparent;
  65 + -webkit-box-shadow: 0 0 0 2px rgba(245, 34, 45, 0);
  66 + box-shadow: 0 0 0 2px rgba(245, 34, 45, 0);
  67 + }
  68 + }
  69 + .ant-calendar-picker:hover .ant-calendar-picker-input:not(.ant-input-disabled) {
  70 + border-color: #f5222d;
  71 + }
  72 + .ant-input-affix-wrapper:hover .ant-input:not(.ant-input-disabled) {
  73 + border-color: #f5222d;
  74 + }
  75 + .form_field_input:focus{
  76 + border-color: #ff4d4f;
  77 + outline: 0;
  78 + -webkit-box-shadow: 0 0 0 2px rgba(245,34,45,0.2);
  79 + box-shadow: 0 0 0 2px rgba(245,34,45,0.2);
  80 + border-right-width: 1px !important;
  81 + }
  82 + .ant-select-selection{
  83 + border-color: #f5222d;
  84 + input:focus{
  85 + border-color:transparent;
  86 + outline: 0;
  87 + -webkit-box-shadow: 0 0 0 2px transparent;
  88 + box-shadow: 0 0 0 2px transparent;
  89 + border-right-width: 1px !important;
  90 + }
  91 + }
  92 + .ant-input-number-focused{
  93 + outline: 0;
  94 + -webkit-box-shadow: 0 0 0 2px rgba(245,34,45,0.2);
  95 + box-shadow: 0 0 0 2px rgba(245,34,45,0.2);
  96 + border-right-width: 1px !important;
  97 + }
  98 + .ant-select-focused{
  99 + .ant-select-selection{
  100 + outline: 0;
  101 + -webkit-box-shadow: 0 0 0 2px rgba(245,34,45,0.2);
  102 + box-shadow: 0 0 0 2px rgba(245,34,45,0.2);
  103 + border-right-width: 1px !important;
  104 + }
  105 + }
  106 + .ant-select-selection:focus, .ant-calendar-picker-input:focus{
  107 + border-color: #ff4d4f;
  108 + outline: 0;
  109 + -webkit-box-shadow: 0 0 0 2px rgba(245,34,45,0.2);
  110 + box-shadow: 0 0 0 2px rgba(245,34,45,0.2);
  111 + border-right-width: 1px !important;
  112 + }
  113 + .ant-calendar-picker-input{
  114 + border-color: #ff4d4f;
  115 + }
  116 + }
  117 + .form_field_label{
  118 + line-height: 36px;
  119 + vertical-align: top;
  120 + display: inline-block;
  121 + // overflow: hidden;
  122 + white-space: nowrap;
  123 + label {
  124 + display: inline-block;
  125 + padding-right: 2px;
  126 + margin-bottom: 0px;
  127 + font-size: 14px;
  128 + font-weight: normal;
  129 + color: rgba(0,0,0,0.65);
  130 + }
  131 + }
  132 + .form_field_label:after,.form_field_label::after{
  133 + content: ":";
  134 + position: relative;
  135 + top: -0.5px;
  136 + padding-right: 4px;
  137 + }
  138 + .form_field_checkbox_hidden_text.form_field_label:after{
  139 + content:"";
  140 + margin-right: 4px;
  141 + }
  142 + .form_field_label_right{
  143 + text-align: right;
  144 + }
  145 + .form_field_label_left{
  146 + text-align: left;
  147 + }
  148 + .form_field_label_center{
  149 + text-align: center;
  150 + }
  151 + .form_field_item_control{
  152 + display: inline-block;
  153 + }
  154 + .form_field_input_cascader{
  155 + .ant-cascader-picker-label{
  156 + z-index: 1;
  157 + }
  158 + }
  159 + .ant-cascader-input{
  160 + .ant-input{
  161 + cursor: pointer;
  162 + }
  163 + }
  164 + .ant-cascader-picker:focus .ant-cascader-input {
  165 + -webkit-box-shadow: 0 0 0 2px rgba(24, 144, 255, 0);
  166 + box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.0);
  167 + }
  168 + .form_field_input_file:hover{
  169 + border-color: #1890ff;
  170 + }
  171 + .form_field_input_file{
  172 + display: table;
  173 + width: 104px;
  174 + height: 104px;
  175 + margin-right: 8px;
  176 + margin-bottom: 8px;
  177 + text-align: center;
  178 + vertical-align: top;
  179 + background-color: #fafafa;
  180 + border: 1px dashed #d9d9d9;
  181 + border-radius: 4px;
  182 + cursor: pointer;
  183 + -webkit-transition: border-color .3s ease;
  184 + transition: border-color .3s ease;
  185 + display: inline-block;
  186 + .form_field_input_file_button_wrap{
  187 + text-align: center;
  188 + padding: 16px 8px;
  189 + i{
  190 + font-size: 32px;
  191 + color: #999;
  192 + }
  193 + .ant-upload-text{
  194 + margin-top: 8px;
  195 + color: #666;
  196 + }
  197 + }
  198 + }
  199 + .form_field_input_file_shows{
  200 + display: inline-block;
  201 + .input_file_shows_item{
  202 + float: left;
  203 + width: 104px;
  204 + height: 104px;
  205 + margin: 0 8px 8px 0;
  206 + position: relative;
  207 + padding: 8px;
  208 + border: 1px solid #d9d9d9;
  209 + border-radius: 4px;
  210 + text-align: center;
  211 + .item-uploading-text{
  212 + margin-top: 18px;
  213 + color: rgba(0,0,0,0.45);
  214 + }
  215 + .item-uploading-progress{
  216 + width: calc(100% - 8px);
  217 + }
  218 + .input_file_shows_item_img{
  219 + width: 100%;
  220 + height: 100%;
  221 + overflow: hidden;
  222 + position: relative;
  223 + img{
  224 + width:100%;
  225 + height:100%;
  226 + min-width: 86px;
  227 + min-height: 86px;
  228 + }
  229 + }
  230 + .input_file_shows_item_mask{
  231 + width: 100%;
  232 + height: 100%;
  233 + overflow: hidden;
  234 + position: absolute;
  235 + .input_file_shows_item_actions{
  236 + position: absolute;
  237 + top: 50%;
  238 + left: 50%;
  239 + z-index: 10;
  240 + white-space: nowrap;
  241 + -webkit-transform: translate(-50%, -50%);
  242 + -ms-transform: translate(-50%, -50%);
  243 + transform: translate(-50%, -50%);
  244 + opacity: 0;
  245 + -webkit-transition: all .3s;
  246 + transition: all .3s;
  247 + i{
  248 + z-index: 10;
  249 + width: 16px;
  250 + margin: 0 4px;
  251 + color: rgba(255,255,255,0.85);
  252 + font-size: 16px;
  253 + cursor: pointer;
  254 + -webkit-transition: all .3s;
  255 + transition: all .3s;
  256 + }
  257 + }
  258 + }
  259 + .input_file_shows_item_mask:hover{
  260 + .input_file_shows_item_actions{
  261 + opacity: 1;
  262 + }
  263 + }
  264 + .input_file_shows_item_mask:hover:before{
  265 + opacity: 1;
  266 + }
  267 + .input_file_shows_item_mask:before{
  268 + position: absolute;
  269 + z-index: 1;
  270 + width: 100%;
  271 + height: 100%;
  272 + background-color: rgba(0,0,0,0.5);
  273 + opacity: 0;
  274 + left: 0;
  275 + bottom: 0;
  276 + -webkit-transition: all .3s;
  277 + transition: all .3s;
  278 + content: ' ';
  279 + }
  280 + }
  281 + }
  282 +}
  283 +
  284 +
  285 +.form_field_group_wrap{
  286 + .form_item_group{
  287 + .form_field_label,.form_group_wrap{
  288 + display: inline-block;
  289 + }
  290 + }
  291 + .form_field_label{
  292 + line-height: 36px;
  293 + vertical-align: top;
  294 + display: inline-block;
  295 + // overflow: hidden;
  296 + white-space: nowrap;
  297 + label {
  298 + display: inline-block;
  299 + padding-right: 2px;
  300 + margin-bottom: 0px;
  301 + font-size: 14px;
  302 + font-weight: normal;
  303 + color: rgba(0,0,0,0.65);
  304 + }
  305 + }
  306 + .form_field_label:after,.form_field_label::after{
  307 + content: ":";
  308 + position: relative;
  309 + top: -0.5px;
  310 + padding-right: 4px;
  311 + }
  312 + .form_field_checkbox_hidden_text.form_field_label:after{
  313 + content:"";
  314 + margin-right: 4px;
  315 + }
  316 + .form_field_label_right{
  317 + text-align: right;
  318 + }
  319 + .form_field_label_left{
  320 + text-align: left;
  321 + }
  322 + .form_field_label_center{
  323 + text-align: center;
  324 + }
  325 + .form_field_item_control{
  326 + display: inline-block;
  327 + }
  328 +}
  329 +
  330 +.redux_search_form_wrap{
  331 + display: flex;
  332 + flex-wrap: wrap;
  333 + padding: 16px 8px;
  334 + background: #fff;
  335 + .search_from_action_warp{
  336 + min-width: 170px;
  337 + text-align: right;
  338 + margin-left: auto;
  339 + .search_form_btn{
  340 + margin-left: 16px;
  341 + }
  342 + }
  343 + // .form_search_field_wrap:first-child{
  344 + // margin-left:0px;
  345 + // }
  346 + .form_search_field_wrap{
  347 + position: relative;
  348 + max-width: 290px;
  349 + min-width: 290px;
  350 + margin-right:24px;
  351 + .form_field_item_wrap{
  352 + min-height: 40px;
  353 + display: flex;
  354 + }
  355 + .form_field_item_with_help{
  356 + color: rgba(0,0,0,0.45);
  357 + line-height: 1.5;
  358 + -webkit-transition: color .3s cubic-bezier(.215, .61, .355, 1);
  359 + transition: color .3s cubic-bezier(.215, .61, .355, 1);
  360 + clear: both;
  361 + }
  362 + .form_field_input_radio_group{
  363 + border:1px solid transparent;
  364 + padding:8px;
  365 + border-radius: 4px;
  366 + }
  367 + .form_field_label{
  368 + line-height: 36px;
  369 + vertical-align: top;
  370 + display: inline-block;
  371 + white-space: nowrap;
  372 + label {
  373 + display: inline-block;
  374 + padding-right: 2px;
  375 + margin-bottom: 0px;
  376 + font-size: 14px;
  377 + font-weight: normal;
  378 + color: rgba(0,0,0,0.65);
  379 + }
  380 + }
  381 + .form_field_label:after,.form_field_label::after{
  382 + content: ":";
  383 + position: relative;
  384 + top: -0.5px;
  385 + padding-right: 4px;
  386 + }
  387 + .form_field_label_right{
  388 + text-align: right;
  389 + }
  390 + .form_field_label_left{
  391 + text-align: left;
  392 + }
  393 + .form_field_label_center{
  394 + text-align: center;
  395 + }
  396 + .form_field_item_control{
  397 + display: inline-block;
  398 + }
  399 + }
  400 +
  401 +}
  402 +
  403 +
  404 +
  405 +
  406 +.redux_step_form_wrap{
  407 + .bottom_butons_wrap{
  408 + width: 100%;
  409 + text-align: center;
  410 + padding: 40px 0;
  411 + .next{
  412 + margin-left: 8px
  413 + }
  414 + .previous{
  415 + margin-right: 8px;
  416 + }
  417 + }
  418 +}
\ No newline at end of file
... ...
  1 +export const required = function required(value) {
  2 + if (Array.isArray(value)) {
  3 + return value.length > 0 ? undefined : '此项是必填项';
  4 + } else if (typeof (value) == 'string' && value && !value.trim()) {
  5 + return value.trim() ? undefined : '此项是必填项';
  6 + } else {
  7 + return typeof (value) == 'number' || value ? undefined : '此项是必填项';
  8 + }
  9 +};
... ...
  1 +import React from 'react';
  2 +import { connect } from 'react-redux';
  3 +import { submit } from 'redux-form';
  4 +import { Form, Icon, Input, Button, Checkbox } from 'antd';
  5 +import cx from 'classnames';
  6 +import ReduxFormWrap from '../components/reduxForm/ReduxFormWrap';
  7 +import InputField from '../components/reduxForm/InputField';
  8 +import { required } from '../components/reduxForm/validate';
  9 +import api from '../utils/api';
  10 +import './login.less';
  11 +
  12 +class Login extends React.Component {
  13 + static propTypes = {
  14 + }
  15 + constructor(props) {
  16 + super(props);
  17 + this.submitLogin = this.submitLogin.bind(this);
  18 + this.backLogin = this.backLogin.bind(this);
  19 + this.state = {
  20 + key: '1'
  21 + };
  22 + }
  23 + componentDidMount() {
  24 + }
  25 + submitLogin(values) {
  26 + const { dispatch } = this.props;
  27 + api.postLogin(values).then(data => {
  28 + console.log(data);
  29 + })
  30 + console.log("#########:::::::", values);
  31 + // if (values.grant_type == 'password') { //密码登录
  32 + // dispatch(login(values));
  33 + // } else if (values.grant_type == 'smscode') {//验证码登录
  34 + // dispatch(login(values));
  35 + // } else if (values.grant_type == 'change_tenant') {//选择tenant
  36 + // dispatch(changeTenant(values));
  37 + // }
  38 + }
  39 + backLogin() {
  40 + const { dispatch } = this.props;
  41 + dispatch({
  42 + type: types.UAA_TENANTS,
  43 + payload: {}
  44 + });
  45 + }
  46 + render() {
  47 + const { key } = this.state;
  48 + const { dispatch, uaa_tenants } = this.props;
  49 + return (
  50 + <div className={cx('login_wrap')}>
  51 + <div className={cx('login_form_wrap', 'padding-16')}>
  52 + <div className={cx('login_form_bgm')}></div>
  53 + <ReduxFormWrap form="login_password" initialValues={{ grant_type: 'password', scope: 'global_access:tenant_admin', username: '18510929499', password: 'a123456' }} className={'mtop-40'}
  54 + onSubmit={this.submitLogin}>
  55 + <InputField width="auto" prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.75)' }} />} placeholder="用户名" name="username" validate={[required]} />
  56 + <InputField width="auto" prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.75)' }} />} placeholder="密码" name="password" validate={[required]} />
  57 + <div className={cx('login_form_item')}>
  58 + <Button type="primary" block onClick={() => {
  59 + dispatch(submit('login_password'))
  60 + }}>登录</Button>
  61 + </div>
  62 + </ReduxFormWrap>
  63 + </div>
  64 + </div >
  65 + );
  66 + }
  67 +}
  68 +
  69 +
  70 +
  71 +const mapState = (state) => {
  72 + const {
  73 + router: { location = {} }
  74 + } = state;
  75 + return {
  76 + location
  77 + };
  78 +};
  79 +export default connect(mapState)(Login);
... ...
  1 +import React from 'react';
  2 +import { connect } from 'react-redux';
  3 +import { Layout } from 'antd';
  4 +import cx from 'classnames';
  5 +
  6 +class HomeContainer extends React.Component {
  7 + static propTypes = {
  8 + }
  9 + constructor(props) {
  10 + super(props);
  11 + }
  12 + componentDidMount() {
  13 + }
  14 + render() {
  15 + return (
  16 + <div className={cx('home_wrap')}>
  17 + page is home
  18 + </div>
  19 + );
  20 + }
  21 +}
  22 +
  23 +
  24 +
  25 +const mapState = (state) => {
  26 + const { router: { location = {} } } = state;
  27 + return {
  28 + location
  29 + };
  30 +};
  31 +export default connect(mapState)(HomeContainer);
... ...
  1 +.login_wrap{
  2 + background: #f3f3f3;
  3 + width: 100vw;
  4 + height: 100vh;
  5 + display: flex;
  6 + padding-right: 200px;
  7 + justify-content:flex-end;
  8 + align-items:center;
  9 + background-image: url(/img/bgm2.jpg);
  10 + background-size: cover;
  11 +}
  12 +.login_form_wrap{
  13 + width: 340px;
  14 + min-height: 300px;
  15 + border-radius: 5px;
  16 + box-shadow: -7px 5px 12px #000;
  17 + background:transparent;
  18 + position: relative;
  19 + .login_form_bgm{
  20 + position: absolute;
  21 + top: 0;
  22 + right: 0;
  23 + left: 0;
  24 + bottom: 0;
  25 + filter: blur(10px);
  26 + background: rgba(0,0,0,.5);
  27 + }
  28 +}
  29 +.login_form_tenants{
  30 + max-height: 230px;
  31 + overflow: auto;
  32 +}
\ No newline at end of file
... ...
  1 +@import './reset.less';
  2 +@import './components.less';
  3 +
  4 +.app_wrap{
  5 + background: #ffffff;
  6 + width: 100vw;
  7 + height: 100vh;
  8 + overflow: hidden;
  9 +}
\ No newline at end of file
... ...
  1 +
  2 +//padding mapping class
  3 +@0px:0px;
  4 +@marginList:4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,72;
  5 +@paddinList:4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,72;
  6 +@directionList:top,right,bottom,left,all;
  7 +//padding-random
  8 +.padding-loop(@direction,@list, @i: 1,@val:extract(@list,@i)) when ((length(@list) >=@i) and not(@direction = all)) {
  9 + .p@{direction}-@{val} {
  10 + padding-@{direction}:@val + @0px;
  11 + }
  12 + .padding-loop(@direction,@list, (@i + 1));
  13 +}
  14 +.padding-loop(@direction,@list, @i: 1,@val:extract(@list,@i)) when (length(@list) >=@i) and (@direction = all) {
  15 + .padding-@{val} {
  16 + padding:@val + @0px;
  17 + }
  18 + .padding-loop(@direction,@list, (@i + 1));
  19 +}
  20 +.padding-loop(extract(@directionList,1),@paddinList);
  21 +.padding-loop(extract(@directionList,2),@paddinList);
  22 +.padding-loop(extract(@directionList,3),@paddinList);
  23 +.padding-loop(extract(@directionList,4),@paddinList);
  24 +.padding-loop(extract(@directionList,5),@paddinList);
  25 +
  26 +//mapping-random
  27 +.mapping-loop(@direction,@list, @i: 1,@val:extract(@list,@i)) when ((length(@list) >=@i) and not(@direction = all)) {
  28 + .m@{direction}-@{val} {
  29 + margin-@{direction}:@val + @0px;
  30 + }
  31 + .mapping-loop(@direction,@list, (@i + 1));
  32 +}
  33 +.mapping-loop(@direction,@list, @i: 1,@val:extract(@list,@i)) when (length(@list) >=@i) and (@direction = all) {
  34 + .margin-@{val} {
  35 + margin:@val + @0px;
  36 + }
  37 + .mapping-loop(@direction,@list, (@i + 1));
  38 +}
  39 +.mapping-loop(extract(@directionList,1),@marginList);
  40 +.mapping-loop(extract(@directionList,2),@marginList);
  41 +.mapping-loop(extract(@directionList,3),@marginList);
  42 +.mapping-loop(extract(@directionList,4),@marginList);
  43 +.mapping-loop(extract(@directionList,5),@marginList);
  44 +
  45 +
  46 +//animation
  47 +@ease-in-out : cubic-bezier(0.645, 0.045, 0.355, 1);
  48 +@animation-duration-slow: 0.3s;
  49 +@animation-duration-base: 0.2s;
  50 +.show-help-motion(@className, @keyframeName, @duration: @animation-duration-slow) {
  51 + .make-motion(@className, @keyframeName, @duration);
  52 + .@{className}-enter,
  53 + .@{className}-appear {
  54 + opacity: 0;
  55 + animation-timing-function: @ease-in-out;
  56 + }
  57 + .@{className}-leave {
  58 + animation-timing-function: @ease-in-out;
  59 + }
  60 +}
  61 +
  62 +.show-help-motion(show-help, antShowHelp, 0.3s);
  63 +
  64 +
  65 +
  66 +.motion-common(@duration: @animation-duration-base) {
  67 + animation-duration: @duration;
  68 + animation-fill-mode: both;
  69 +}
  70 +
  71 +.motion-common-leave(@duration: @animation-duration-base) {
  72 + animation-duration: @duration;
  73 + animation-fill-mode: both;
  74 +}
  75 +
  76 +.make-motion(@className, @keyframeName, @duration: @animation-duration-base) {
  77 + .@{className}-enter,
  78 + .@{className}-appear {
  79 + .motion-common(@duration);
  80 + animation-play-state: paused;
  81 + }
  82 + .@{className}-leave {
  83 + .motion-common-leave(@duration);
  84 + animation-play-state: paused;
  85 + }
  86 + .@{className}-enter.@{className}-enter-active,
  87 + .@{className}-appear.@{className}-appear-active {
  88 + animation-name: ~'@{keyframeName}In';
  89 + animation-play-state: running;
  90 + }
  91 + .@{className}-leave.@{className}-leave-active {
  92 + animation-name: ~'@{keyframeName}Out';
  93 + animation-play-state: running;
  94 + pointer-events: none;
  95 + }
  96 +}
  97 +
  98 +.text-left{
  99 + text-align: left;
  100 +}
  101 +.text-right{
  102 + text-align: right;
  103 +}
  104 +.text-center{
  105 + text-align: center;
  106 +}
\ No newline at end of file
... ...
  1 +/*! normalize.css v3.0.2 | MIT License | git.io/normalize */
  2 +
  3 +/**
  4 + * 1. Set default font family to sans-serif.
  5 + * 2. Prevent iOS text size adjust after orientation change, without disabling
  6 + * user zoom.
  7 + */
  8 +
  9 +html {
  10 + font-family: sans-serif; /* 1 */
  11 + -ms-text-size-adjust: 100%; /* 2 */
  12 + -webkit-text-size-adjust: 100%; /* 2 */
  13 +}
  14 +
  15 +/**
  16 + * Remove default margin.
  17 + */
  18 +
  19 +body {
  20 + margin: 0;
  21 +}
  22 +
  23 +/* HTML5 display definitions
  24 + ========================================================================== */
  25 +
  26 +/**
  27 + * Correct `block` display not defined for any HTML5 element in IE 8/9.
  28 + * Correct `block` display not defined for `details` or `summary` in IE 10/11
  29 + * and Firefox.
  30 + * Correct `block` display not defined for `main` in IE 11.
  31 + */
  32 +
  33 +article,
  34 +aside,
  35 +details,
  36 +figcaption,
  37 +figure,
  38 +footer,
  39 +header,
  40 +hgroup,
  41 +main,
  42 +menu,
  43 +nav,
  44 +section,
  45 +summary {
  46 + display: block;
  47 +}
  48 +
  49 +/**
  50 + * 1. Correct `inline-block` display not defined in IE 8/9.
  51 + * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
  52 + */
  53 +
  54 +audio,
  55 +canvas,
  56 +progress,
  57 +video {
  58 + display: inline-block; /* 1 */
  59 + vertical-align: baseline; /* 2 */
  60 +}
  61 +
  62 +/**
  63 + * Prevent modern browsers from displaying `audio` without controls.
  64 + * Remove excess height in iOS 5 devices.
  65 + */
  66 +
  67 +audio:not([controls]) {
  68 + display: none;
  69 + height: 0;
  70 +}
  71 +
  72 +/**
  73 + * Address `[hidden]` styling not present in IE 8/9/10.
  74 + * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
  75 + */
  76 +
  77 +[hidden],
  78 +template {
  79 + display: none;
  80 +}
  81 +
  82 +/* Links
  83 + ========================================================================== */
  84 +
  85 +/**
  86 + * Remove the gray background color from active links in IE 10.
  87 + */
  88 +
  89 +a {
  90 + background-color: transparent;
  91 +}
  92 +
  93 +/**
  94 + * Improve readability when focused and also mouse hovered in all browsers.
  95 + */
  96 +
  97 +a:active,
  98 +a:hover {
  99 + outline: 0;
  100 +}
  101 +
  102 +/* Text-level semantics
  103 + ========================================================================== */
  104 +
  105 +/**
  106 + * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
  107 + */
  108 +
  109 +abbr[title] {
  110 + border-bottom: 1px dotted;
  111 +}
  112 +
  113 +/**
  114 + * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
  115 + */
  116 +
  117 +b,
  118 +strong {
  119 + font-weight: bold;
  120 +}
  121 +
  122 +/**
  123 + * Address styling not present in Safari and Chrome.
  124 + */
  125 +
  126 +dfn {
  127 + font-style: italic;
  128 +}
  129 +
  130 +/**
  131 + * Address variable `h1` font-size and margin within `section` and `article`
  132 + * contexts in Firefox 4+, Safari, and Chrome.
  133 + */
  134 +
  135 +h1 {
  136 + font-size: 2em;
  137 + margin: 0.67em 0;
  138 +}
  139 +
  140 +/**
  141 + * Address styling not present in IE 8/9.
  142 + */
  143 +
  144 +mark {
  145 + background: #ff0;
  146 + color: #000;
  147 +}
  148 +
  149 +/**
  150 + * Address inconsistent and variable font size in all browsers.
  151 + */
  152 +
  153 +small {
  154 + font-size: 80%;
  155 +}
  156 +
  157 +/**
  158 + * Prevent `sub` and `sup` affecting `line-height` in all browsers.
  159 + */
  160 +
  161 +sub,
  162 +sup {
  163 + font-size: 75%;
  164 + line-height: 0;
  165 + position: relative;
  166 + vertical-align: baseline;
  167 +}
  168 +
  169 +sup {
  170 + top: -0.5em;
  171 +}
  172 +
  173 +sub {
  174 + bottom: -0.25em;
  175 +}
  176 +
  177 +/* Embedded content
  178 + ========================================================================== */
  179 +
  180 +/**
  181 + * Remove border when inside `a` element in IE 8/9/10.
  182 + */
  183 +
  184 +img {
  185 + border: 0;
  186 +}
  187 +
  188 +/**
  189 + * Correct overflow not hidden in IE 9/10/11.
  190 + */
  191 +
  192 +svg:not(:root) {
  193 + overflow: hidden;
  194 +}
  195 +
  196 +/* Grouping content
  197 + ========================================================================== */
  198 +
  199 +/**
  200 + * Address margin not present in IE 8/9 and Safari.
  201 + */
  202 +
  203 +figure {
  204 + margin: 1em 40px;
  205 +}
  206 +
  207 +/**
  208 + * Address differences between Firefox and other browsers.
  209 + */
  210 +
  211 +hr {
  212 + -moz-box-sizing: border-box;
  213 + box-sizing: border-box;
  214 + height: 0;
  215 +}
  216 +
  217 +/**
  218 + * Contain overflow in all browsers.
  219 + */
  220 +
  221 +pre {
  222 + overflow: auto;
  223 +}
  224 +
  225 +/**
  226 + * Address odd `em`-unit font size rendering in all browsers.
  227 + */
  228 +
  229 +code,
  230 +kbd,
  231 +pre,
  232 +samp {
  233 + font-family: monospace, monospace;
  234 + font-size: 1em;
  235 +}
  236 +
  237 +/* Forms
  238 + ========================================================================== */
  239 +
  240 +/**
  241 + * Known limitation: by default, Chrome and Safari on OS X allow very limited
  242 + * styling of `select`, unless a `border` property is set.
  243 + */
  244 +
  245 +/**
  246 + * 1. Correct color not being inherited.
  247 + * Known issue: affects color of disabled elements.
  248 + * 2. Correct font properties not being inherited.
  249 + * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
  250 + */
  251 +
  252 +button,
  253 +input,
  254 +optgroup,
  255 +select,
  256 +textarea {
  257 + color: inherit; /* 1 */
  258 + font: inherit; /* 2 */
  259 + margin: 0; /* 3 */
  260 +}
  261 +
  262 +/**
  263 + * Address `overflow` set to `hidden` in IE 8/9/10/11.
  264 + */
  265 +
  266 +button {
  267 + overflow: visible;
  268 +}
  269 +
  270 +/**
  271 + * Address inconsistent `text-transform` inheritance for `button` and `select`.
  272 + * All other form control elements do not inherit `text-transform` values.
  273 + * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
  274 + * Correct `select` style inheritance in Firefox.
  275 + */
  276 +
  277 +button,
  278 +select {
  279 + text-transform: none;
  280 +}
  281 +
  282 +/**
  283 + * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
  284 + * and `video` controls.
  285 + * 2. Correct inability to style clickable `input` types in iOS.
  286 + * 3. Improve usability and consistency of cursor style between image-type
  287 + * `input` and others.
  288 + */
  289 +
  290 +button,
  291 +html input[type="button"], /* 1 */
  292 +input[type="reset"],
  293 +input[type="submit"] {
  294 + -webkit-appearance: button; /* 2 */
  295 + cursor: pointer; /* 3 */
  296 +}
  297 +
  298 +/**
  299 + * Re-set default cursor for disabled elements.
  300 + */
  301 +
  302 +button[disabled],
  303 +html input[disabled] {
  304 + cursor: default;
  305 +}
  306 +
  307 +/**
  308 + * Remove inner padding and border in Firefox 4+.
  309 + */
  310 +
  311 +button::-moz-focus-inner,
  312 +input::-moz-focus-inner {
  313 + border: 0;
  314 + padding: 0;
  315 +}
  316 +
  317 +/**
  318 + * Address Firefox 4+ setting `line-height` on `input` using `!important` in
  319 + * the UA stylesheet.
  320 + */
  321 +
  322 +input {
  323 + line-height: normal;
  324 +}
  325 +
  326 +/**
  327 + * It's recommended that you don't attempt to style these elements.
  328 + * Firefox's implementation doesn't respect box-sizing, padding, or width.
  329 + *
  330 + * 1. Address box sizing set to `border-box` in IE 8/9/10.
  331 + * 2. Remove excess padding in IE 8/9/10.
  332 + */
  333 +
  334 +input[type="checkbox"],
  335 +input[type="radio"] {
  336 + box-sizing: border-box; /* 1 */
  337 + padding: 0; /* 2 */
  338 +}
  339 +
  340 +/**
  341 + * Fix the cursor style for Chrome's increment/decrement buttons. For certain
  342 + * `font-size` values of the `input`, it causes the cursor style of the
  343 + * decrement button to change from `default` to `text`.
  344 + */
  345 +
  346 +input[type="number"]::-webkit-inner-spin-button,
  347 +input[type="number"]::-webkit-outer-spin-button {
  348 + height: auto;
  349 +}
  350 +
  351 +/**
  352 + * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
  353 + * 2. Address `box-sizing` set to `border-box` in Safari and Chrome
  354 + * (include `-moz` to future-proof).
  355 + */
  356 +
  357 +input[type="search"] {
  358 + -webkit-appearance: textfield; /* 1 */
  359 + -moz-box-sizing: border-box;
  360 + -webkit-box-sizing: border-box; /* 2 */
  361 + box-sizing: border-box;
  362 +}
  363 +
  364 +/**
  365 + * Remove inner padding and search cancel button in Safari and Chrome on OS X.
  366 + * Safari (but not Chrome) clips the cancel button when the search input has
  367 + * padding (and `textfield` appearance).
  368 + */
  369 +
  370 +input[type="search"]::-webkit-search-cancel-button,
  371 +input[type="search"]::-webkit-search-decoration {
  372 + -webkit-appearance: none;
  373 +}
  374 +
  375 +/**
  376 + * Define consistent border, margin, and padding.
  377 + */
  378 +
  379 +fieldset {
  380 + border: 1px solid #c0c0c0;
  381 + margin: 0 2px;
  382 + padding: 0.35em 0.625em 0.75em;
  383 +}
  384 +
  385 +/**
  386 + * 1. Correct `color` not being inherited in IE 8/9/10/11.
  387 + * 2. Remove padding so people aren't caught out if they zero out fieldsets.
  388 + */
  389 +
  390 +legend {
  391 + border: 0; /* 1 */
  392 + padding: 0; /* 2 */
  393 +}
  394 +
  395 +/**
  396 + * Remove default vertical scrollbar in IE 8/9/10/11.
  397 + */
  398 +
  399 +textarea {
  400 + overflow: auto;
  401 +}
  402 +
  403 +/**
  404 + * Don't inherit the `font-weight` (applied by a rule above).
  405 + * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
  406 + */
  407 +
  408 +optgroup {
  409 + font-weight: bold;
  410 +}
  411 +
  412 +/* Tables
  413 + ========================================================================== */
  414 +
  415 +/**
  416 + * Remove most spacing between table cells.
  417 + */
  418 +
  419 +table {
  420 + border-collapse: collapse;
  421 + border-spacing: 0;
  422 +}
  423 +
  424 +td,
  425 +th {
  426 + padding: 0;
  427 +}
  428 +
  429 +*{
  430 + -ms-box-sizing:border-box;
  431 + -moz-box-sizing:border-box;
  432 + -webkit-box-sizing:border-box;
  433 + box-sizing:border-box;
  434 +}
\ No newline at end of file
... ...
  1 +/*接口调用通用状态 */
  2 +export const FETCH = 'FETCH';
  3 +export const FETCH_SUBMITTING = 'FETCH_SUBMITTING';
  4 +export const FETCH_SUCCESS = 'FETCH_SUCCESS';
  5 +export const FETCH_FAIL = 'FETCH_FAIL';
  6 +export const FETCH_X_REQUEST_ID = 'FETCH_X_REQUEST_ID';
  7 +export const FETCH_FORM_NAME = 'FETCH_FORM_NAME';
  8 +
  9 +/*系统操作 */
  10 +export const SYSTEM_MENU_SELECTED_KEYS = 'SYSTEM_MENU_SELECTED_KEYS';
\ No newline at end of file
... ...
  1 +// import { reducer as formReducer } from './uaa';
  2 +import { delay } from 'redux-saga';
  3 +import { put, takeEvery, all } from 'redux-saga/effects';
  4 +import reduxform from './reduxform';
  5 +import system from './system';
  6 +
  7 +
  8 +function* incrementAsync() {
  9 + yield delay(1000);
  10 + yield put({ type: 'INCREMENT' });
  11 +}
  12 +
  13 +
  14 +function* watchIncrementAsync() {
  15 + yield takeEvery('INCREMENT_ASYNC', incrementAsync);
  16 +}
  17 +
  18 +function* helloSaga() {
  19 + yield 5;
  20 + console.log('Hello Sagas!');
  21 +}
  22 +
  23 +// notice how we now only export the rootSaga
  24 +// single entry point to start all Sagas at once
  25 +export default function* createSagaRoot() {
  26 + yield all([
  27 + ...reduxform,
  28 + ...system,
  29 + helloSaga(),
  30 + watchIncrementAsync()
  31 + ]);
  32 +}
  33 +
  34 +
  35 +
  36 +
... ...
  1 +import { take, select, call, takeEvery, put } from 'redux-saga/effects';
  2 +import { change, submit, initialize } from 'redux-form';
  3 +import * as types from '../actionTypes';
  4 +import api from '../../utils/api';
  5 +import { dispatch } from '../../utils/commonUtils';
  6 +
  7 +
  8 +/*
  9 + * 表单初始化后自动加载load
  10 + */
  11 +function* initLoadSearchForm(action) {
  12 + while (true) {
  13 + const searchAction = yield take('@@redux-form/INITIALIZE');
  14 + const { meta = {}, payload = {} } = searchAction;
  15 + if (payload.auto_load) {
  16 + const { form } = meta;
  17 + dispatch(submit(form));
  18 + }
  19 + }
  20 +}
  21 +
  22 +export default [initLoadSearchForm()];
... ...
  1 +import { take, select, call, takeEvery, put } from 'redux-saga/effects';
  2 +import * as types from '../actionTypes';
  3 +import { getSystemSelect } from '../../utils/commonUtils';
  4 +
  5 +//切换菜单
  6 +export const changeSystemMenu = (values) => {
  7 + return { type: types.SYSTEM_MENU_SELECTED_KEYS, payload: values };
  8 +};
  9 +/*
  10 +* 路由改变菜单回填
  11 +*/
  12 +export function* selectSysMenus(uaa_perms) {
  13 + const state = yield select();
  14 + const { router } = state;
  15 + const { location = {} } = router;
  16 + const { pathname = '' } = location;
  17 + if (uaa_perms.length > 0) {
  18 + const menuAction = getSystemSelect(pathname, uaa_perms);
  19 + yield put({
  20 + type: types.SYSTEM_MENU_SELECTED_KEYS,
  21 + payload: menuAction
  22 + });
  23 + }
  24 +}
  25 +/*
  26 +路由跳转切点,做页面权限判断
  27 +*/
  28 +function* handldRouter() {
  29 + while (true) {
  30 + const routerAction = yield take(['@@router/LOCATION_CHANGE']);
  31 + const state = yield select();
  32 + const { payload = {} } = routerAction;
  33 + const { location = {} } = payload;
  34 + const { pathname = '' } = location;
  35 + // const { uaa: { uaa_perms = [] } } = state;
  36 + // yield selectSysMenus(uaa_perms);
  37 + yield selectSysMenus([]);
  38 + }
  39 +}
  40 +
  41 +export default [handldRouter()];
\ No newline at end of file
... ...
  1 +import fetch from './fetch';
  2 +import system from './system';
  3 +
  4 +export default {
  5 + fetch,
  6 + system
  7 +};
\ No newline at end of file
... ...
  1 +import reduceReducers from 'reduce-reducers';
  2 +import * as types from '../actionTypes';
  3 +import { typeToLowerCase, reducerFactory } from '../../utils/commonUtils';
  4 +
  5 +const initialState = {
  6 + [typeToLowerCase(types.FETCH_FAIL)]: false,
  7 + [typeToLowerCase(types.FETCH_SUBMITTING)]: false,
  8 + [typeToLowerCase(types.FETCH_SUCCESS)]: false,
  9 + [typeToLowerCase(types.FETCH_FORM_NAME)]: ''
  10 +};
  11 +
  12 +
  13 +export default reduceReducers(initialState, reducerFactory);
\ No newline at end of file
... ...
  1 +import { combineReducers } from 'redux';
  2 +import { connectRouter } from 'connected-react-router';
  3 +import { reducer as formReducer } from 'redux-form';
  4 +import createReducer from './createReducer';
  5 +
  6 +
  7 +export default (history) => combineReducers({
  8 + router: connectRouter(history),
  9 + form: formReducer,
  10 + ...createReducer
  11 +});
... ...
  1 +import reduceReducers from 'reduce-reducers';
  2 +import * as types from '../actionTypes';
  3 +import { typeToLowerCase, reducerFactory } from '../../utils/commonUtils';
  4 +
  5 +const initialState = {
  6 + [typeToLowerCase(types.SYSTEM_MENU_SELECTED_KEYS)]: { openKeys: [], selectedKeys: [] }
  7 +};
  8 +
  9 +export default reduceReducers(initialState, reducerFactory);
\ No newline at end of file
... ...
  1 +import { createHashHistory } from "history";
  2 +import { applyMiddleware, compose, createStore } from 'redux';
  3 +import { routerMiddleware } from 'connected-react-router';
  4 +import 'regenerator-runtime/runtime';// 这个 runtime 必须在 redux-saga 之前引入
  5 +import createSagaMiddleware from 'redux-saga';
  6 +import createRootReducer from './reducers';
  7 +import createSagaRoot, { helloSaga } from './actions';
  8 +
  9 +export const history = createHashHistory();//createBrowserHistory();
  10 +
  11 +const initialState = {};
  12 +const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
  13 +const sagaMiddleware = createSagaMiddleware();
  14 +const createStoreWithMiddleware = composeEnhancers(
  15 + applyMiddleware(
  16 + routerMiddleware(history),
  17 + sagaMiddleware
  18 + )
  19 +);
  20 +
  21 +const store = createStore(
  22 + createRootReducer(history),
  23 + initialState,
  24 + createStoreWithMiddleware
  25 +);
  26 +sagaMiddleware.run(createSagaRoot);
  27 +export default store;
\ No newline at end of file
... ...
  1 +import React from 'react';
  2 +import Loadable from 'react-loadable';
  3 +
  4 +const MyLoadingComponent = ({ pastDelay, error, retry }) => {
  5 + // 加载中
  6 + if (pastDelay) {
  7 + return (
  8 + <div style={{ height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
  9 + <div style={{ display: 'inline-block', marginTop: '-80px' }}></div>
  10 + <div style={{ marginLeft: '-30px' }}>页面加载中...</div>
  11 + </div>);
  12 + }
  13 + // 加载出错
  14 + else if (error) {
  15 + console.log(error)
  16 + return (
  17 + <div style={{ height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
  18 + <div>
  19 + 加载页面失败,点击
  20 + <a onClick={retry}>重新加载</a>
  21 + </div>
  22 + </div>);
  23 + }
  24 + else {
  25 + return null;
  26 + }
  27 +};
  28 +const AsyncComponent = loadComponent => (
  29 + Loadable({
  30 + loader: loadComponent,
  31 + loading: MyLoadingComponent
  32 + })
  33 +);
  34 +
  35 +export default AsyncComponent;
\ No newline at end of file
... ...
  1 +import React from 'react';
  2 +import { Route, Switch } from "react-router";
  3 +import asyncComponent from '../AsyncComponent';
  4 +
  5 +//首页
  6 +const HomeContainer = asyncComponent(
  7 + () => import(/* webpackChunkName: "home" */'../../containers/home')
  8 +);
  9 +
  10 +const homeRoute = (match) => {
  11 + return (
  12 + <Switch>
  13 + {/* 首页 */}
  14 + <Route exact={true} path={`${match.path}/home`} component={HomeContainer} />
  15 + </Switch>
  16 + );
  17 +};
  18 +
  19 +export default homeRoute;
\ No newline at end of file
... ...
  1 +import React from 'react';
  2 +import { Route, Switch } from 'react-router';
  3 +import { ConnectedRouter } from 'connected-react-router';
  4 +import LayoutRoute from './layout/LayoutRoute';
  5 +import LoginRoute from "./layout/LoginRoute";
  6 +
  7 +class AppRoutes extends React.Component {
  8 + constructor(props) {
  9 + super(props);
  10 + }
  11 + componentDidMount() { }
  12 + componentWillUnmount() { }
  13 + render() {
  14 + const { history } = this.props;
  15 + if (!history)
  16 + return null;
  17 + return (
  18 + <ConnectedRouter history={history}>
  19 + <Switch>
  20 + <Route path="/main" component={LayoutRoute} />
  21 + <Route path="/login" component={LoginRoute} />
  22 + <Route render={() => (<div>Miss</div>)} />
  23 + </Switch>
  24 + </ConnectedRouter >
  25 + );
  26 + }
  27 +}
  28 +export default AppRoutes;
\ No newline at end of file
... ...
  1 +import React from 'react';
  2 +import { connect } from 'react-redux';
  3 +import { Layout, Button } from 'antd';
  4 +import SysMenu from '../../components/reduxAntd/SysMenu';
  5 +import cx from 'classnames';
  6 +import homeRoute from '../home';
  7 +
  8 +const { Header, Sider, Content } = Layout;
  9 +
  10 +
  11 +
  12 +class LayoutRoute extends React.Component {
  13 + static propTypes = {
  14 + }
  15 + constructor(props) {
  16 + super(props);
  17 + this.renderLoad = this.renderLoad.bind(this);
  18 + }
  19 + componentDidMount() {
  20 + const { uaa_tenant, dispatch } = this.props;
  21 +
  22 + }
  23 + changeMenu(menu) {
  24 + const { key } = menu;
  25 + console.log(key);
  26 + if ('logout' == key) {
  27 + document.location.href = '/signOut';
  28 + } else if ('percenter_pwdsetting' == key) {
  29 + document.location.href = '#/main/setting/changePassword';
  30 + }
  31 + }
  32 + renderLoad() {
  33 + return (
  34 + <div style={{ textAlign: 'center', margin: '300px auto' }}>
  35 + <div className="sk-folding-cube">
  36 + <div className="sk-cube1 sk-cube"></div>
  37 + <div className="sk-cube2 sk-cube"></div>
  38 + <div className="sk-cube4 sk-cube"></div>
  39 + <div className="sk-cube3 sk-cube"></div>
  40 + </div>
  41 + 页面数据加载中...
  42 + </div>
  43 + );
  44 + }
  45 + render() {
  46 + const { match, location: { pathname } } = this.props;
  47 + return (
  48 + <Layout className={cx("layout-wrap")}>
  49 + <Header className={cx("layout-header-wrap")} style={{ background: '#529CE2', padding: '0 25px' }}>
  50 + headcccc
  51 + <a href="/signOut">退出</a>
  52 + </Header>
  53 + <Layout className={cx("layout-content-wrap")}>
  54 + <Sider className="layout-sider-wrap" collapsedWidth={0} collapsible={false} width={180}>
  55 + <div>
  56 + <SysMenu></SysMenu>
  57 + </div>
  58 + </Sider>
  59 + <Content>
  60 + <div className="app-routes-wrap">
  61 + {homeRoute(match)}
  62 + </div>
  63 + </Content>
  64 + </Layout>
  65 + </Layout>
  66 + );
  67 + }
  68 +}
  69 +
  70 +
  71 +
  72 +const mapState = (state) => {
  73 + const {
  74 + router = {}
  75 + } = state;
  76 + return {
  77 + router
  78 + };
  79 +};
  80 +export default connect(mapState)(LayoutRoute);
\ No newline at end of file
... ...
  1 +import React from 'react';
  2 +import { connect } from 'react-redux';
  3 +import cx from 'classnames';
  4 +import Login from '../../containers/Login';
  5 +
  6 +class LoginRoute extends React.Component {
  7 + static propTypes = {
  8 + }
  9 + constructor(props) {
  10 + super(props);
  11 + }
  12 + componentDidMount() {
  13 + }
  14 + render() {
  15 + return (
  16 + <div className={cx('')}>
  17 + <Login />
  18 + </div>
  19 + );
  20 + }
  21 +}
  22 +
  23 +
  24 +
  25 +const mapState = (state) => {
  26 + const { router = {} } = state;
  27 + return {
  28 + router
  29 + };
  30 +};
  31 +export default connect(mapState)(LoginRoute);
... ...
  1 +import localforage from "localforage";
  2 +
  3 +let localStore;
  4 +const getLocalForage = (name = 'app') => {
  5 + if (!localStore) {
  6 + localStore = localforage.createInstance({
  7 + name: name,
  8 + storeName: name
  9 + });
  10 + }
  11 + return localStore;
  12 +};
  13 +
  14 +export default getLocalForage;
\ No newline at end of file
... ...
  1 +import * as login from "./login";
  2 +
  3 +export default {
  4 + ...login,
  5 +};
\ No newline at end of file
... ...
  1 +import store from '../redux/store';
  2 +
  3 +/*
  4 +*key转小写
  5 +*/
  6 +export const typeToLowerCase = (type) => {
  7 + if (type && typeof (type) === 'string') {
  8 + return type.toLowerCase();
  9 + } else {
  10 + return type;
  11 + }
  12 +};
  13 +/*
  14 +*reducer生成方法
  15 +*/
  16 +export const reducerFactory = (state = {}, action = {}) => {
  17 + const { payload, type } = action;
  18 + if (state && state.hasOwnProperty(typeToLowerCase(type))) {
  19 + return { ...state, [typeToLowerCase(type)]: payload };
  20 + } else {
  21 + return state;
  22 + }
  23 +};
  24 +
  25 +export const dispatch = (action) => {
  26 + return store.dispatch(action);
  27 +};
  28 +
  29 +/*
  30 +*修改路由
  31 +*/
  32 +export const pushRoute = (url) => {
  33 + document.location.href = `#${url}`;
  34 +};
  35 +/*
  36 +获取当前选中的菜单
  37 +*/
  38 +export const getSystemSelect = (pathname, perms) => {
  39 + let moduleName = '', openKeys = [], selectedKeys = [];
  40 + if (pathname && pathname.indexOf('/main/') != -1 && pathname.split("/").length > 2) {
  41 + const pathArray = pathname.split("/");
  42 + moduleName = pathArray[2];
  43 + }
  44 + perms.map((perm, i) => {
  45 + if (perm.module == moduleName) {
  46 + selectedKeys = [moduleName];
  47 + if (perm.parent_module) {
  48 + openKeys = [perm.parent_module];
  49 + }
  50 + }
  51 + });
  52 + return {
  53 + openKeys,
  54 + selectedKeys
  55 + };
  56 +};
\ No newline at end of file
... ...
  1 +import 'es6-promise';
  2 +import fetch from 'isomorphic-fetch';
  3 +import getLocalForage from '../storage/localForage';
  4 +import { dispatch } from './commonUtils';
  5 +import * as types from '../redux/actionTypes';
  6 +import uuidv1 from 'uuid/v1';
  7 +//请求后端环境
  8 +let SERVER_DOMAIN = '/';
  9 +// if (window.evn == 'production') {
  10 +// SERVER_DOMAIN = window.PRODUCTION_SERVER_DOMAIN;
  11 +// } else if (window.evn == 'development') {
  12 +// SERVER_DOMAIN = window.DEVELOPMENT_SERVER_DOMAIN;
  13 +// } else if (window.evn == 'test') {
  14 +// SERVER_DOMAIN = window.TEST_SERVER_DOMAIN;
  15 +// }
  16 +
  17 +export const api_version = 'v1';
  18 +const checkStatus = (response) => {
  19 + switch (response.status) {
  20 + case 200:
  21 + return response;
  22 + case 409:
  23 + return response;
  24 + case 400:
  25 + return response;
  26 + case 401:
  27 + dispatch({
  28 + type: types.FETCH_FAIL,
  29 + payload: '用户认证授权失败',
  30 + meta: {
  31 + title: '用户认证授权失败',
  32 + description: '当前请求没有认证授权,请重新登录'
  33 + }
  34 + });
  35 + return response;
  36 + default:
  37 + return response;
  38 + }
  39 +};
  40 +
  41 +const handleErrorStatus = (errorJSon = {}, data) => {
  42 + const { code, errors, message, title, x_request_id } = errorJSon;
  43 + const { __form_name = '' } = data, fields = [];
  44 + switch (code) {
  45 + case 400:
  46 + break;
  47 + case 401:
  48 + dispatch({
  49 + type: types.FETCH_FAIL,
  50 + payload: { message, errors, title, x_request_id }
  51 + });
  52 + break;
  53 + default:
  54 + break;
  55 + }
  56 + console.log(__form_name);
  57 + if (__form_name) {
  58 + dispatch({
  59 + type: '@@redux-form/SET_SUBMIT_FINALLY',
  60 + meta: {
  61 + form: __form_name,
  62 + fields: fields,
  63 + error: true
  64 + }
  65 + });
  66 + }
  67 +};
  68 +
  69 +const parseJSON = (response, data) => {
  70 + let backJson;
  71 + try {
  72 + backJson = response.json();
  73 + handleErrorStatus(backJson, data);
  74 + } catch (error) {
  75 + backJson = {};
  76 + dispatch({
  77 + type: types.FETCH_FAIL,
  78 + payload: '解析JSON失败'
  79 + });
  80 + }
  81 + return backJson;
  82 +};
  83 +const redirectFun = (back) => {
  84 + if (back && back.redirect) {
  85 + window.location.href = back.redirect;
  86 + }
  87 + return back;
  88 +};
  89 +
  90 +const getToken = () => {
  91 + return getLocalForage().getItem('tokens').then(function (value) {
  92 + const { access_token = '' } = value || {};
  93 + console.log(value);
  94 + return access_token;
  95 + }).catch(function (err) {
  96 + console.log(err);
  97 + return err;
  98 + });
  99 +};
  100 +
  101 +const fetchCatch = (err) => {
  102 + console.log(err);
  103 + dispatch({
  104 + type: '@@redux-form/SET_SUBMIT_FINALLY',
  105 + meta: {
  106 + form: '',
  107 + fields: [],
  108 + error: true
  109 + }
  110 + });
  111 + return err;
  112 +};
  113 +
  114 +export const get = function* (url) {
  115 + const token = yield getToken();
  116 + const defaultOpt = {
  117 + method: 'get',
  118 + headers: {
  119 + 'Accept': 'application/json',
  120 + 'Content-Type': 'application/json',
  121 + 'Authorization': `Bearer ${token}`,
  122 + 'Request-ID': uuidv1()
  123 + },
  124 + credentials: 'same-origin',
  125 + timeout: 1000 * 300
  126 + };
  127 + return yield fetch(`${SERVER_DOMAIN}${url}`, defaultOpt).then(checkStatus).then((response) => {
  128 + return parseJSON(response, unSerializeParams(url));
  129 + }).then(redirectFun).catch(fetchCatch);
  130 +};
  131 +
  132 +export const post = function* (url, data = {}) {
  133 + const token = yield getToken();
  134 + const defaultOpt = {
  135 + method: 'post',
  136 + headers: {
  137 + 'Accept': 'application/json',
  138 + 'Content-Type': 'application/json',
  139 + 'Authorization': `Bearer ${token}`,
  140 + 'Request-ID': uuidv1()
  141 + },
  142 + credentials: 'same-origin',
  143 + timeout: 1000 * 600,
  144 + body: JSON.stringify(data)
  145 + }; console.log("postpostpostpostpost", SERVER_DOMAIN, url);
  146 + return yield fetch(`${SERVER_DOMAIN}${url}`, defaultOpt).then(checkStatus).then((response) => {
  147 + return parseJSON(response, data);
  148 + }).catch(fetchCatch);
  149 +};
  150 +
  151 +export const postFile = function* (url, data = {}) {
  152 + const token = yield getToken();
  153 + const defaultOpt = {
  154 + method: 'post',
  155 + headers: {
  156 + 'Accept': 'application/json',
  157 + 'Authorization': `Bearer ${token}`,
  158 + 'Request-ID': uuidv1()
  159 + },
  160 + credentials: 'same-origin',
  161 + timeout: 1000 * 300,
  162 + body: data
  163 + };
  164 + return yield fetch(`${SERVER_DOMAIN}${url}`, defaultOpt).then(checkStatus).then(parseJSON).catch(fetchCatch);
  165 +};
  166 +
  167 +export const put = function* (url, data = {}) {
  168 + const token = yield getToken();
  169 + const defaultOpt = {
  170 + method: 'put',
  171 + headers: {
  172 + 'Accept': 'application/json',
  173 + 'Content-Type': 'application/json',
  174 + 'Authorization': `Bearer ${token}`,
  175 + 'Request-ID': uuidv1()
  176 + },
  177 + credentials: 'same-origin',
  178 + timeout: 1000 * 300,
  179 + body: JSON.stringify(data)
  180 + };
  181 + return yield fetch(`${SERVER_DOMAIN}${url}`, defaultOpt).then(checkStatus).then(parseJSON).catch(fetchCatch);
  182 +};
  183 +
  184 +export const del = function* (url, data = {}) {
  185 + const token = yield getToken();
  186 + const defaultOpt = {
  187 + method: 'delete',
  188 + headers: {
  189 + 'Accept': 'application/json',
  190 + 'Content-Type': 'application/json',
  191 + 'Authorization': `Bearer ${token}`,
  192 + 'Request-ID': uuidv1()
  193 + },
  194 + credentials: 'same-origin',
  195 + timeout: 1000 * 300
  196 + };
  197 + return yield fetch(`${SERVER_DOMAIN}${url}`, defaultOpt).then(checkStatus).then(parseJSON).catch(fetchCatch);
  198 +};
  199 +
  200 +export const head = function* (url, data = {}) {
  201 + const token = yield getToken();
  202 + const defaultOpt = {
  203 + method: 'head',
  204 + headers: {
  205 + 'Accept': 'application/json',
  206 + 'Content-Type': 'application/json',
  207 + 'Authorization': `Bearer ${token}`,
  208 + 'Request-ID': uuidv1()
  209 + },
  210 + credentials: 'same-origin',
  211 + timeout: 1000 * 300,
  212 + body: JSON.stringify(data)
  213 + };
  214 + return yield fetch(`${SERVER_DOMAIN}${url}`, defaultOpt).then(checkStatus).then(parseJSON).catch(fetchCatch);
  215 +};
  216 +
  217 +export const patch = function* (url, data = {}) {
  218 + const token = yield getToken();
  219 + const defaultOpt = {
  220 + method: 'patch',
  221 + headers: {
  222 + 'Accept': 'application/json',
  223 + 'Content-Type': 'application/x-www-form-urlencoded',
  224 + 'Authorization': `Bearer ${token}`,
  225 + 'Request-ID': uuidv1()
  226 + },
  227 + credentials: 'same-origin',
  228 + timeout: 1000 * 300,
  229 + body: JSON.stringify(data)
  230 + };
  231 + return yield fetch(`${SERVER_DOMAIN}${url}`, defaultOpt).then(checkStatus).then(parseJSON).catch(fetchCatch);
  232 +};
  233 +
  234 +export const json = function* (url) {
  235 + const token = yield getToken();
  236 + const defaultOpt = {
  237 + method: 'get',
  238 + headers: {
  239 + 'Accept': 'application/json',
  240 + 'Content-Type': 'application/json',
  241 + 'Authorization': `Bearer ${token}`,
  242 + 'Request-ID': uuidv1()
  243 + },
  244 + credentials: 'same-origin',
  245 + timeout: 1000 * 300
  246 + };
  247 + return yield fetch(`${SERVER_DOMAIN}${url}`, defaultOpt).then(checkStatus).then(parseJSON).catch(fetchCatch);
  248 +};
  249 +
  250 +export const postJson = function* (url, data = {}) {
  251 + const token = yield getToken();
  252 + const defaultOpt = {
  253 + method: 'post',
  254 + headers: {
  255 + 'Accept': 'application/json',
  256 + 'Content-Type': 'application/json',
  257 + 'Authorization': `Bearer ${token}`,
  258 + 'Request-ID': uuidv1()
  259 + },
  260 + credentials: 'same-origin',
  261 + timeout: 1000 * 600,
  262 + body: JSON.stringify(data)
  263 + };
  264 + return yield fetch(`${SERVER_DOMAIN}${url}`, defaultOpt).then(checkStatus).then(parseJSON).catch(fetchCatch);
  265 +};
  266 +
  267 +export const putJson = function* (url, data = {}) {
  268 + const token = yield getToken();
  269 + const defaultOpt = {
  270 + method: 'put',
  271 + headers: {
  272 + 'Accept': 'application/json',
  273 + 'Content-Type': 'application/json',
  274 + 'Authorization': `Bearer ${token}`,
  275 + 'Request-ID': uuidv1()
  276 + },
  277 + credentials: 'same-origin',
  278 + timeout: 1000 * 300,
  279 + body: JSON.stringify(data)
  280 + };
  281 + return yield fetch(`${SERVER_DOMAIN}${url}`, defaultOpt).then(checkStatus).then(parseJSON).catch(fetchCatch);
  282 +};
  283 +
  284 +export const patchJson = function* (url, data = {}) {
  285 + const token = yield getToken();
  286 + const defaultOpt = {
  287 + method: 'patch',
  288 + headers: {
  289 + 'Accept': 'application/json',
  290 + 'Content-Type': 'application/json',
  291 + 'Authorization': `Bearer ${token}`,
  292 + 'Request-ID': uuidv1()
  293 + },
  294 + credentials: 'same-origin',
  295 + timeout: 1000 * 300,
  296 + body: JSON.stringify(data)
  297 + };
  298 + return yield fetch(`${SERVER_DOMAIN}${url}`, defaultOpt).then(checkStatus).then(parseJSON).catch(fetchCatch);
  299 +};
  300 +
  301 +export const serializeParams = (params) => {
  302 + if (params && typeof (params) === "object") {
  303 + const keys = Object.keys(params);
  304 + let stringParams = ['?t=1'];
  305 + keys.map((key, i) => {
  306 + stringParams.push(key + "=" + encodeURIComponent(params[key]));
  307 + });
  308 + return stringParams.join("&");
  309 + } else if (params && typeof (params) === "string") {
  310 + return params;
  311 + } else {
  312 + return '';
  313 + }
  314 +};
  315 +
  316 +export const unSerializeParams = (url) => {
  317 + const backParmas = {};
  318 + if (url && typeof (url) === "string" && url.indexOf("?") != -1) {
  319 + let parmas = [];
  320 + if (url.split("?")[1]) {
  321 + parmas = url.split("?")[1].split("&");
  322 + }
  323 + parmas.map((parma, i) => {
  324 + if (parma && parma.indexOf("=" != -1)) {
  325 + const temp = parma.split("=");
  326 + backParmas[temp[0]] = decodeURIComponent(temp[1]);
  327 + }
  328 + });
  329 + return backParmas;
  330 + } else {
  331 + return backParmas;
  332 + }
  333 +};
  334 +
  335 +
  336 +export async function ajaxGet(url) {
  337 + let token = '';
  338 + await getLocalForage().getItem('tokens').then(function (value) {
  339 + const { access_token = '' } = value || {};
  340 + token = access_token;
  341 + return access_token;
  342 + }).catch(function (err) {
  343 + console.log(err);
  344 + return err;
  345 + });
  346 + const defaultOpt = {
  347 + method: 'get',
  348 + headers: {
  349 + 'Accept': 'application/json',
  350 + 'Content-Type': 'application/json',
  351 + 'Authorization': `Bearer ${token}`,
  352 + 'Request-ID': uuidv1()
  353 + },
  354 + credentials: 'same-origin',
  355 + timeout: 1000 * 300
  356 + };
  357 + return fetch(`${SERVER_DOMAIN}${url}`, defaultOpt).then(checkStatus).then((response) => {
  358 + return parseJSON(response, unSerializeParams(url));
  359 + }).then(redirectFun).catch(fetchCatch);
  360 +}
  361 +
  362 +export async function ajaxPost(url, data = {}) {
  363 + let token = '';
  364 + await getLocalForage().getItem('tokens').then(function (value) {
  365 + const { access_token = '' } = value || {};
  366 + token = access_token;
  367 + return access_token;
  368 + }).catch(function (err) {
  369 + console.log(err);
  370 + return err;
  371 + });
  372 + const defaultOpt = {
  373 + method: 'post',
  374 + headers: {
  375 + 'Accept': 'application/json',
  376 + 'Content-Type': 'application/json',
  377 + 'Authorization': `Bearer ${token}`,
  378 + 'Request-ID': uuidv1()
  379 + },
  380 + credentials: 'same-origin',
  381 + timeout: 1000 * 600,
  382 + body: JSON.stringify(data)
  383 + };
  384 + return fetch(`${SERVER_DOMAIN}${url}`, defaultOpt).then(checkStatus).then((response) => {
  385 + return parseJSON(response, data);
  386 + }).catch(fetchCatch);
  387 +}
\ No newline at end of file
... ...
  1 +import * as fetch from './fetch';
  2 +
  3 +/*
  4 +* 登录
  5 +*/
  6 +export const postLogin = (data) => {
  7 + const url = `login`;
  8 + return fetch.ajaxPost(url, data);
  9 +};
  10 +
... ...
注册登录 后发表评论