美文网首页
Ant Design Pro学习之组件化

Ant Design Pro学习之组件化

作者: 小马将过河 | 来源:发表于2019-04-24 10:52 被阅读0次

    同事写了一个我目前看着比较正规化的组件式页面,在此作为学习标准贴一下,先看个效果图:


    列表 编辑1 编辑2

    这是一个oauth的client管理的页面,主要代码如下:
    api列表数据结构

    {
        "code": 0,
        "message": "操作成功",
        "data": {
            "content": [
                {
                    "clientId": "usercenter-manage",
                    "clientName": "测试app",
                    "resourceIds": "usercenter/manage,smscenter/api",
                    "clientSecret": "",
                    "scope": "read,write,trust",
                    "authorizedGrantTypes": "password,refresh_token",
                    "webServerRedirectUri": null,
                    "authorities": null,
                    "accessTokenValidity": 7200,
                    "refreshTokenValidity": null,
                    "additionalInformation": null,
                    "autoapprove": null,
                    "smsCodeLength": 4,
                    "smsCodeExpire": 10,
                    "smsCodeSign": "【xxxxxx】",
                    "platformCode": null,
                    "updateTime": "2019-03-25T14:27:26.000+0000",
                    "createTime": null
                }
            ],
            "pageable": {
                "sort": {
                    "sorted": true,
                    "unsorted": false,
                    "empty": false
                },
                "offset": 0,
                "pageSize": 10,
                "pageNumber": 0,
                "paged": true,
                "unpaged": false
            },
            "totalPages": 1,
            "totalElements": 9,
            "last": true,
            "size": 10,
            "number": 0,
            "first": true,
            "numberOfElements": 9,
            "sort": {
                "sorted": true,
                "unsorted": false,
                "empty": false
            },
            "empty": false
        }
    }
    

    组件化嘛,文件自然比较多,打个标识

    1、ClientList:页面渲染js

    import React, { PureComponent } from 'react';
    import { connect } from 'dva';
    import { Popconfirm, Card, Table, Button, Divider, Tag, message } from 'antd';
    import PageHeaderWrapper from '@/components/PageHeaderWrapper';
    import DescriptionList from '@/components/DescriptionList';
    import ClientForm from './ClientForm';
    import { humanizeTime, getOAuthTypeNames } from './ClientUtil';
    import styles from '../Common/TableList.less';
    
    const { Description } = DescriptionList;
    
    @connect(({ client, loading }) => ({
      client,
      loading: loading.effects['client/fetch'],
      submitting: loading.effects['client/update'],
    }))
    class ClientList extends PureComponent {
      columns = [
        {
          title: '应用ID',
          dataIndex: 'clientId',
        },
        {
          title: '应用名称',
          dataIndex: 'clientName',
        },
        {
          title: (
            <span>
              Token
              <br />
              有效期
            </span>
          ),
          dataIndex: 'accessTokenValidity',
          render: value => humanizeTime(value),
        },
        {
          title: (
            <span>
              RefreshToken
              <br />
              有效期
            </span>
          ),
          dataIndex: 'refreshTokenValidity',
          render: value => humanizeTime(value),
        },
        {
          title: '操作',
          dataIndex: 'action',
          render: (text, record) => (
            <span>
              <a
                onClick={() => {
                  this.handleOpenForm(record);
                }}
              >
                编辑
              </a>
              <Divider type="vertical" />
              <Popconfirm
                title="确认删除?"
                onConfirm={() => {
                  this.handleRemove(record);
                }}
                okText="确认"
                cancelText="取消"
              >
                <a href="#">删除</a>
              </Popconfirm>
            </span>
          ),
        },
      ];
    
      componentDidMount() {
        const { dispatch } = this.props;
        dispatch({ type: 'client/fetch' });
      }
    
      handleTableChange = pagination => {
        const { current, pageSize } = pagination;
        const { dispatch } = this.props;
        dispatch({ type: 'client/fetch', payload: { page: current - 1, size: pageSize } });
      };
    
      handleTableExpand = record => {
        const toTags = items => items.map((value, index) => <Tag key={index}>{value}</Tag>);
        return (
          <div>
            <DescriptionList size="small">
              <Description term="授权模式">
                {toTags(getOAuthTypeNames(record.authorizedGrantTypes))}
              </Description>
              <Description term="平台编码">{record.platformCode}</Description>
              <Description term="资源IDS">{record.resourceIds}</Description>
            </DescriptionList>
            <DescriptionList style={{ marginTop: 15 }} size="small">
              <Description term="短信验证码长度">{record.smsCodeLength}</Description>
              <Description term="短信验证码有效期">
                {record.smsCodeLength ? `${record.smsCodeLength}分钟` : ''}
              </Description>
              <Description term="短信验证码签名">{record.smsCodeSign}</Description>
            </DescriptionList>
          </div>
        );
      };
    
      handleOpenForm = formData => {
        const { dispatch } = this.props;
        dispatch({ type: 'client/openForm', payload: formData });
      };
    
      handleCloseForm = () => {
        const { dispatch } = this.props;
        dispatch({ type: 'client/closeForm' });
      };
    
      handleAdd = values => {
        const { dispatch } = this.props;
        dispatch({ type: 'client/update', payload: values }).then(() => {
          message.success('操作成功');
        });
      };
    
      handleRemove = record => {
        const { dispatch } = this.props;
        dispatch({ type: 'client/remove', payload: record.clientId }).then(() => {
          message.success('删除成功');
        });
      };
    
      render() {
        const {
          client: { list, form },
          loading,
          submitting,
        } = this.props;
        const paginationProps = {
          showSizeChanger: true,
          showQuickJumper: true,
          ...list.pagination,
        };
        return (
          <PageHeaderWrapper title="应用列表">
            <Card bordered={false}>
              <div className={styles.tableList}>
                <div className={styles.tableListForm} />
                <div className={styles.tableListOperator}>
                  <Button icon="plus" type="primary" onClick={this.handleOpenForm}>
                    新建
                  </Button>
                </div>
                <Table
                  rowKey="clientId"
                  size="middle"
                  columns={this.columns}
                  loading={loading}
                  dataSource={list.data}
                  pagination={paginationProps}
                  onChange={this.handleTableChange}
                  expandedRowRender={this.handleTableExpand}
                />
              </div>
            </Card>
            <ClientForm
              data={form.data}
              visible={form.visible}
              submitting={submitting}
              onClose={this.handleCloseForm}
              onSave={this.handleAdd}
            />
          </PageHeaderWrapper>
        );
      }
    }
    
    export default ClientList;
    
    

    2、ClientForm:添加编辑单条数据的Form

    import React, { PureComponent } from 'react';
    import { Modal, Form, Input, Tabs, InputNumber } from 'antd';
    import SecretInput from './SecretInput';
    import PeriodInput from './PeriodInput';
    import GrantTypeInput from './GrantTypeInput';
    import SmsSignInput from './SmsSignInput';
    
    const { Item: FormItem } = Form;
    const { TabPane } = Tabs;
    
    @Form.create()
    class ClientForm extends PureComponent {
      state = {
        tabKey: '1',
      };
    
      reset = () => {
        const { form } = this.props;
        form.resetFields();
        this.setState({ tabKey: '1' });
      };
    
      render() {
        const { data, visible, submitting, onSave, onClose, form } = this.props;
        const { tabKey } = this.state;
        const formItemLayout = {
          labelCol: { span: 5 },
          wrapperCol: { span: 15 },
        };
        const title = data.clientId ? '更新应用' : '添加应用';
        return (
          <Modal
            style={{ top: 10 }}
            width={800}
            title={title}
            visible={visible}
            confirmLoading={submitting}
            onCancel={() => {
              this.reset();
              onClose();
            }}
            onOk={() => {
              form.validateFields((err, values) => {
                if (!err) onSave(values);
                else this.setState({ tabKey: '1' });
              });
            }}
          >
            <Form>
              <Tabs
                tabPosition="left"
                activeKey={tabKey}
                onChange={activeKey => this.setState({ tabKey: activeKey })}
              >
                <TabPane tab="授权设置" key="1">
                  <FormItem label="应用ID" {...formItemLayout}>
                    {form.getFieldDecorator('clientId', {
                      rules: [
                        {
                          type: 'string',
                          required: true,
                          message: '应用ID不能为空!',
                        },
                      ],
                      initialValue: data.clientId,
                    })(<Input disabled={!!data.clientId} />)}
                  </FormItem>
                  <FormItem label="应用名称" {...formItemLayout}>
                    {form.getFieldDecorator('clientName', {
                      rules: [
                        {
                          type: 'string',
                          required: true,
                          message: '应用名称不能为空!',
                        },
                      ],
                      initialValue: data.clientName,
                    })(<Input />)}
                  </FormItem>
                  <FormItem label="资源IDs" {...formItemLayout}>
                    {form.getFieldDecorator('resourceIds', {
                      rules: [
                        {
                          type: 'string',
                          required: true,
                          message: '资源IDs不能为空!',
                        },
                      ],
                      initialValue: data.resourceIds,
                    })(<Input />)}
                  </FormItem>
                  <FormItem label="授权类型" {...formItemLayout}>
                    {form.getFieldDecorator('authorizedGrantTypes', {
                      rules: [
                        {
                          type: 'string',
                          required: true,
                          message: '请选择授权类型!',
                        },
                      ],
                      initialValue: data.authorizedGrantTypes,
                    })(<GrantTypeInput />)}
                  </FormItem>
                  <FormItem label="Token有效期" {...formItemLayout}>
                    {form.getFieldDecorator('accessTokenValidity', {
                      initialValue: _.defaultTo(data.accessTokenValidity, ''),
                    })(<PeriodInput />)}
                  </FormItem>
                  <FormItem label="Refresh有效期" {...formItemLayout}>
                    {form.getFieldDecorator('refreshTokenValidity', {
                      initialValue: _.defaultTo(data.refreshTokenValidity, ''),
                    })(<PeriodInput />)}
                  </FormItem>
                  <FormItem label="秘钥" {...formItemLayout}>
                    {form.getFieldDecorator('clientSecret', {
                      initialValue: _.defaultTo(data.clientSecret, ''),
                    })(<SecretInput />)}
                  </FormItem>
                </TabPane>
                <TabPane tab="短信设置" key="2">
                  <FormItem label="验证码长度" {...formItemLayout}>
                    {form.getFieldDecorator('smsCodeLength', {
                      initialValue: data.smsCodeLength,
                    })(<InputNumber min={1} style={{ width: 300 }} />)}
                  </FormItem>
                  <FormItem label="验证码有效期(分钟)" {...formItemLayout}>
                    {form.getFieldDecorator('smsCodeExpire', {
                      initialValue: data.smsCodeExpire,
                    })(<InputNumber min={1} style={{ width: 300 }} />)}
                  </FormItem>
                 <FormItem label="验证码签名" {...formItemLayout}>
                    {form.getFieldDecorator('smsCodeSign', {
                      initialValue: data.smsCodeSign,
                    })(<SmsSignInput />)}
                  </FormItem>
                </TabPane>
              </Tabs>
            </Form>
          </Modal>
        );
      }
    }
    
    export default ClientForm;
    
    

    3、ClientUtil.js

    import _ from 'lodash';
    import moment from 'moment';
    export const authTypes = [
      { name: '授权码模式', value: 'authorization_code' },
      { name: '简化模式', value: 'implicit' },
      { name: '密码模式', value: 'password' },
      { name: '客户端模式', value: 'client_credentials' },
      { name: '刷新模式', value: 'refresh_token' },
    ];
    export function getOAuthTypeNames(str) {
      if (!str) return [];
      const values = str.split(',');
      return values.map(value => _.find(authTypes, t => t.value === value).name);
    }
    export function getResources(str) {
      if (!str) return [];
      return str.split(',');
    }
    export function humanizeTime(value) {
      let timeText = '';
      if (value) {
        timeText = moment.duration(value, 'seconds').humanize();
      } else {
        timeText = '未设置';
      }
      return timeText;
    }
    

    4、GrantTypeInput组件GrantTypeInput.js

    GrantTypeInput
    import React, { PureComponent } from 'react';
    import { Select } from 'antd';
    import { authTypes } from './ClientUtil';
    
    const { Option } = Select;
    
    class GrantTypeInput extends PureComponent {
      state = {
        value: [],
      };
    
      componentWillMount() {
        const { props } = this;
        if (props.value) {
          const value = props.value ? props.value.split(',') : [];
          this.setState({ value });
        }
      }
    
      componentWillReceiveProps(nextProps) {
        const { props } = this;
        if (props.value !== nextProps.value && !nextProps.value) {
          this.setState({ value: [] });
        } else {
          const value = nextProps.value ? nextProps.value.split(',') : [];
          this.setState({ value });
        }
      }
    
      handleSelectChange = value => {
        const { onChange } = this.props;
        this.setState({ value });
        if (onChange) onChange(value.join(','));
      };
    
      render() {
        const { value } = this.state;
        return (
          <Select
            style={{ width: '100%' }}
            mode="multiple"
            value={value}
            onChange={this.handleSelectChange}
          >
            {authTypes.map((type, index) => (
              <Option key={index} value={type.value}>
                {type.name}
              </Option>
            ))}
          </Select>
        );
      }
    }
    
    export default GrantTypeInput;
    
    

    5、token有效期输入组件PeriodInput.js

    PeriodInput.js
    import React, { PureComponent } from 'react';
    import moment from 'moment';
    
    import { Input, Select } from 'antd';
    
    const { Option } = Select;
    
    const getTime = (time, fromUnit, toUnit) => moment.duration(Number(time), fromUnit).as(toUnit);
    
    export const timeUnits = [
      { name: '秒', value: 'seconds' },
      { name: '分钟', value: 'minutes' },
      { name: '小时', value: 'hours' },
      { name: '天', value: 'days' },
    ];
    
    class PeriodInput extends PureComponent {
      state = {
        value: '',
        unit: 'seconds',
      };
    
      componentWillMount() {
        const { props } = this;
        if (props.value) {
          this.setState({
            unit: 'seconds',
            value: props.value,
          });
        }
      }
    
      componentWillReceiveProps(nextProps) {
        const { props } = this;
        if (props.value !== nextProps.value && !nextProps.value) {
          this.setState({
            unit: 'seconds',
            value: '',
          });
        } else {
          this.setState({
            unit: 'seconds',
            value: nextProps.value,
          });
        }
      }
    
      handleSelectChange = unitValue => {
        const { unit, value } = this.state;
        const newValue = value ? getTime(value, unit, unitValue) : '';
        this.setState({
          unit: unitValue,
          value: newValue,
        });
      };
    
      onChangeValue = e => {
        const { value } = e.target;
        const { unit } = this.state;
        const { onChange } = this.props;
        const seconds = getTime(value, unit, 'seconds');
        this.setState({ value });
        if (onChange) onChange(seconds);
      };
    
      render() {
        const { unit, value } = this.state;
        return (
          <Input
            value={value}
            onChange={this.onChangeValue}
            addonAfter={
              <Select style={{ width: 80 }} value={unit} onChange={this.handleSelectChange}>
                {timeUnits.map(t => (
                  <Option key={t.value} value={t.value}>
                    {t.name}
                  </Option>
                ))}
              </Select>
            }
          />
        );
      }
    }
    
    export default PeriodInput;
    
    

    6、秘钥生成组件SecretInput.js

    SecretInput
    import React, { PureComponent } from 'react';
    import { Row, Col, Slider, Input } from 'antd';
    import random from '@/utils/random';
    
    const minValue = 10;
    const maxValue = 30;
    const defaultState = {
      visible: false,
      value: '',
      length: 10,
    };
    
    class SecretInput extends PureComponent {
      state = { ...defaultState };
    
      componentWillMount() {
        const { props } = this;
        if (props.value) {
          this.setState({ value: props.value });
        }
      }
    
      componentWillReceiveProps(nextProps) {
        const { props } = this;
        if (props.value !== nextProps.value && !nextProps.value) {
          this.setState({ ...defaultState });
        } else {
          this.setState({ value: nextProps.value });
        }
      }
    
      handleCreatePwd = () => {
        const { length } = this.state;
        this.setState({ visible: true });
        this.handleChangeLength(length);
      };
    
      handleChangeLength = length => {
        const value = random.generate(length);
        this.setState({ length });
        this.handleChangeValue(value);
      };
    
      handleChangeValue = value => {
        const { onChange } = this.props;
        this.setState({ value });
        if (onChange) onChange(value);
      };
    
      render() {
        const { visible, value, length } = this.state;
        return (
          <div>
            <Row gutter={8}>
              <Col span={20}>
                <Input value={value} onChange={this.handleChangeValue} />
              </Col>
              <Col span={4}>
                <a onClick={this.handleCreatePwd}>随机生成</a>
              </Col>
            </Row>
            {visible ? (
              <Row>
                <Col span={20}>
                  <Slider
                    min={minValue}
                    max={maxValue}
                    value={length}
                    onChange={this.handleChangeLength}
                  />
                </Col>
              </Row>
            ) : null}
          </div>
        );
      }
    }
    
    export default SecretInput;
    

    7、短信签名:输入内容与数据库保存不一致,前端正则加减括号

    import React, { PureComponent } from 'react';
    import { Input } from 'antd';
    
    const removeBrackets = value => (value ? value.replace(/[【】]/g, '') : '');
    const addBrackets = value => (value ? `【${value}】` : '');
    
    class SmsSignInput extends PureComponent {
      state = {
        value: '',
      };
    
      componentWillMount() {
        const { props } = this;
        if (props.value) this.setStateValue(props.value);
      }
    
      componentWillReceiveProps(nextProps) {
        const { props } = this;
        if (props.value !== nextProps.value && !nextProps.value) {
          this.setStateValue('');
        } else {
          this.setStateValue(nextProps.value);
        }
      }
    
      setStateValue = value => {
        this.setState({ value: removeBrackets(value) });
      };
    
      handleChangeValue = e => {
        const { value } = e.target;
        const { onChange } = this.props;
        this.setState({ value });
        if (onChange) onChange(addBrackets(value));
      };
    
      render() {
        const { value } = this.state;
        const { props } = this;
        return <Input {...props} value={value} onChange={this.handleChangeValue} />;
      }
    }
    
    export default SmsSignInput;
    
    

    相关文章

      网友评论

          本文标题:Ant Design Pro学习之组件化

          本文链接:https://www.haomeiwen.com/subject/vatwvqtx.html