【共享单车】—— React后台管理系统开发手记:项目工程化开发

前言:以下内容基于React全家桶+AntD实战课程的学习实践过程记录。最终成果github地址:https://github.com/66Web/react-antd-manager,欢迎star。


一、项目工程化概念 

 

二、BaseForm的封装

城市管理中FilterForm子组件:

订单管理中FilterForm子组件:

员工管理中FilterForm子组件:

【项目工程化】:表单封装

  • components->BaseForm->index.js
  • 关键:抽象出formList,根据formList中的item.type判断要渲染的AnTD表单类型
    const formList = this.props.formList;  
  • 实现表单数据的双向绑定:getFieldDecorator
    const {getFieldDecorator } = this.props.form;
    
    <FormItem label={label} key={field}>
              {
                  getFieldDecorator([field])(
                       <Input type="text" style={{width: width}} placeholder={placeholder}/>
                  )
              }
    </FormItem>  
  • 获取组件中全部表单控件的内容:getFieldsValue()
    handleFilterSubmit = () => {
            let fieldsValue = this.props.form.getFieldsValue();
            this.props.filterSubmit(fieldsValue);
    }
    
    //order->index.js中
    <BaseForm formList={this.formList} filterSubmit={this.handleFilter}/>
    
    handleFilter = (params) => {
            this.params = params;
            this.requestList();
    }
  • order->index.js中:按照AntD 的getFieldDecorator.option规则定义formList数据 

    formList = [
            { 
                type: 'SELECT',
                label: '城市',
                field: 'city_id',
                placeholder: '全部',
                initialValue: '1',
                width: 80,
                list: [
                    {id: '0', name: '全部'},
                    {id: '1', name: '北京'},
                    {id: '2', name: '天津'},
                    {id: '3', name: '上海'}
                ]
            },
            { 
                type: '时间查询'
            },
            { 
                type: 'SELECT',
                label: '订单状态',
                field: 'order_status',
                placeholder: '全部',
                initialValue: '1',
                width: 80,
                list: [
                    {id: '0', name: '全部'},
                    {id: '1', name: '进行中'},
                    {id: '2', name: '结束行程'}
                ]
            }
        ]
  • BaseForm组件代码:

    import React from 'react'
    import { Input, Select, Form, Button, Checkbox, DatePicker} from 'antd'
    import Utils from '../../utils/utils'
    const FormItem = Form.Item;
    
    class FilterForm extends React.Component{
        
        handleFilterSubmit = () => {
            let fieldsValue = this.props.form.getFieldsValue();
            this.props.filterSubmit(fieldsValue);
        }
    
        reset = () => {
            this.props.form.resetFields();
        }
    
        initFormList = () => {
            const {getFieldDecorator } = this.props.form;
            const formList = this.props.formList;
            const formItemList = [];
            if(formList && formList.length>0){
                formList.forEach((item, i) => {
                     let label = item.label;
                     let field = item.field;
                     let initialValue = item.initialValue || '';
                     let placeholder = item.placeholder;
                     let width = item.width;
                     if(item.type == '时间查询'){
                        const begin_time = <FormItem label="订单时间" key={field}>
                                {
                                    getFieldDecorator('begin_time')(
                                        <DatePicker showTime={true} placeholder={placeholder} format="YYYY-MM-DD HH:mm:ss"/>
                                    )
                                }
                        </FormItem>;
                        formItemList.push(begin_time);
                        //~后省略冒号:label="~" colon={false} 
                        const end_time = <FormItem key={field}>
                                {
                                    getFieldDecorator('end_time')(
                                        <DatePicker showTime={true} placeholder={placeholder} format="YYYY-MM-DD HH:mm:ss"/>
                                    )
                                }
                        </FormItem>;
                        formItemList.push(end_time);
                     }else if(item.type == 'INPUT'){
                        const INPUT = <FormItem label={label} key={field}>
                              {
                                   getFieldDecorator([field])(
                                      <Input type="text" style={{width: width}} placeholder={placeholder}/>
                                   )
                              }
                        </FormItem>;
                        formItemList.push(INPUT);
                    }else if(item.type == 'SELECT'){
                         const SELECT = <FormItem label={label} key={field}>
                               {
                                    getFieldDecorator([field],{
                                        initialValue: initialValue
                                    })(
                                        <Select
                                            style={{width: width}}
                                            placeholder={[placeholder]}
                                        >
                                            {Utils.getOptionList(item.list)}
                                        </Select>
                                    )
                               }
                         </FormItem>;
                         formItemList.push(SELECT);
                     }else if(item.type == 'CHECKBOX'){
                        const CHECKBOX = <FormItem label={label} key={field}>
                              {
                                   getFieldDecorator([field],{
                                       valuePropName: 'checked',
                                       initialValue: initialValue //true | false
                                   })(
                                       <Checkbox>
                                           {label}
                                       </Checkbox>
                                   )
                              }
                        </FormItem>;
                        formItemList.push(CHECKBOX);
                    }else if(item.type == 'DATE'){
                        const DATEPICKER = <FormItem label={label} key={field}>
                              {
                                   getFieldDecorator([field])(
                                       <DatePicker showTime={true} placeholder={placeholder} format="YYYY-MM-DD HH:mm:ss"/>
                                   )
                              }
                        </FormItem>;
                        formItemList.push(DATEPICKER);
                    }
                })
            }
            return formItemList;
        }
    
        render(){
            return (
                <Form layout="inline">
                    {this.initFormList()}
                    <FormItem>
                        <Button type="primary" style={{margin:'0 10px'}} onClick={this.handleFilterSubmit}>查询</Button>
                        <Button onClick={this.reset}>重置</Button>
                    </FormItem>
                </Form>
            )
        }
    }
    export default Form.create({})(FilterForm)
    

 

三、列表数据请求封装

每个管理模块几乎都有一个requestList()调用axios.ajax请求Easy Mock接口中的数据。

依据【项目工程化】思想,封装这部分代码,简化开发过程。

  • src->axios->index.js中:定义requestList方法,接收_this、url、params、isMock参数
    static requestList(_this, url, params, isMock){
             var data = {
                 params: params,
                 isMock //使用Mock数据
             }
             this.ajax({
                 url,
                 data
             }).then((data) => {
                 if(data && data.list){
                    let list = data.list.item_list.map((item, index) => {
                        item.key = index;
                        return item;
                    });
                    _this.setState({
                        list,
                        selectedRowKeys: [],//重置
                        pagination:Utils.pagination(data,(current)=>{
                            _this.params.page = current;
                            _this.requestList();
                        })
                    })
                 }
             })
    }
  • order->index.js中:requestList()中直接调用axios.requestList()即可获取接口数据

    requestList = () => {
            axios.requestList(this, '/order/list', this.params, true)
    }
    

 

四、ETable表格封装

原城市管理、订单管理:数据列表实现都需要以下内容

<div className="content-wrap">
       <Table 
               bordered
               columns={columns}
               dataSource={this.state.list}
               pagination={this.state.pagination}
               rowSelection= {rowSelection}
               onRow={(record, index) => {
                     return {
                         onClick: () => {
                              this.onRowClick(record, index);
                         }
                      }
               }}
       />
</div>

单选列表项:定义selectedRowKeys和rowSelection、监听onRow事件

const selectedRowKeys = this.state.selectedRowKeys;
const rowSelection = {
        type: 'radio',
        selectedRowKeys
} 
onRowClick = (record, index) => {
        let selectKey = [index];
        this.setState({
            selectedRowKeys: selectKey,
            selectedItem: record
        })
}

【项目工程化】:封装可复用代码,扩展复选列表项功能

  • utils->uitils.js:添加ETable行点击通用函数,判断选择框变更传入的参数是否有selectedIds,设置不同的state内容
     /**
         * ETable 行点击通用函数
         * @param {*选中行的索引} selectedRowKeys
         * @param {*选中行对象} selectedItem
     */
    updateSelectedItem(selectedRowKeys, selectedRows, selectedIds) {
            if (selectedIds) {
                this.setState({
                    selectedRowKeys,
                    selectedIds: selectedIds,
                    selectedItem: selectedRows
                })
            } else {
                this.setState({
                    selectedRowKeys,
                    selectedItem: selectedRows
                })
            }
    }
  • components->ETable->index.js传入的this.props中若有selectedIds,设置checkbox渲染数据,否则,设置radio

    import React from 'react'
    import Utils from '../../utils/utils'
    import {Table} from 'antd'
    import  "./index.less"
    export default class ETable extends React.Component {
    
        state = {}
        //处理行点击事件
        onRowClick = (record, index) => {
            let rowSelection = this.props.rowSelection;
            if(rowSelection == 'checkbox'){
                let selectedRowKeys = this.props.selectedRowKeys;
                let selectedIds = this.props.selectedIds;
                let selectedItem = this.props.selectedItem || [];
                if (selectedIds) {
                    const i = selectedIds.indexOf(record.id);
                    if (i == -1) {//避免重复添加
                        selectedIds.push(record.id)
                        selectedRowKeys.push(index);
                        selectedItem.push(record);
                    }else{
                        selectedIds.splice(i,1);
                        selectedRowKeys.splice(i,1);
                        selectedItem.splice(i,1);
                    }
                } else {
                    selectedIds = [record.id];
                    selectedRowKeys = [index]
                    selectedItem = [record];
                }
                this.props.updateSelectedItem(selectedRowKeys,selectedItem || {},selectedIds);
            }else{
                let selectKey = [index];
                const selectedRowKeys = this.props.selectedRowKeys;
                if (selectedRowKeys && selectedRowKeys[0] == index){
                    return;
                }
                this.props.updateSelectedItem(selectKey,record || {});
            }
        };
    
        // 选择框变更
        onSelectChange = (selectedRowKeys, selectedRows) => {
            let rowSelection = this.props.rowSelection;
            const selectedIds = [];
            if(rowSelection == 'checkbox'){
                selectedRows.map((item)=>{
                    selectedIds.push(item.id);
                });
                this.setState({
                    selectedRowKeys,
                    selectedIds:selectedIds,
                    selectedItem: selectedRows[0]
                });
            }
            this.props.updateSelectedItem(selectedRowKeys,selectedRows[0],selectedIds);
        };
    
        onSelectAll = (selected, selectedRows, changeRows) => {
            let selectedIds = [];
            let selectKey = [];
            selectedRows.forEach((item,i)=> {
                selectedIds.push(item.id);
                selectKey.push(i);
            });
            this.props.updateSelectedItem(selectKey,selectedRows[0] || {},selectedIds);
        }
    
        getOptions = () => {
            let p = this.props;
            const name_list = {
                "订单编号":170,
                "车辆编号":80,
                "手机号码":96,
                "用户姓名":70,
                "密码":70,
                "运维区域":300,
                "车型":42,
                "故障编号":76,
                "代理商编码":97,
                "角色ID":64
            };
            if (p.columns && p.columns.length > 0) {
                p.columns.forEach((item)=> {
                    //开始/结束 时间
                    if(!item.title){
                        return
                    }
                    if(!item.width){
                        if(item.title.indexOf("时间") > -1 && item.title.indexOf("持续时间") < 0){
                            item.width = 132
                        }else if(item.title.indexOf("图片") > -1){
                            item.width = 86
                        }else if(item.title.indexOf("权限") > -1 || item.title.indexOf("负责城市") > -1){
                            item.width = '40%';
                            item.className = "text-left";
                        }else{
                            if(name_list[item.title]){
                                item.width = name_list[item.title];
                            }
                        }
                    }
                    item.bordered = true;
                });
            }
            const { selectedRowKeys } = this.props;
            const rowSelection = {
                type: 'radio',
                selectedRowKeys,
                onChange: this.onSelectChange,
                onSelect:(record, selected, selectedRows)=>{
                    console.log('...')
                },
                onSelectAll:this.onSelectAll
            };
            let row_selection = this.props.rowSelection;
            // 当属性未false或者null时,说明没有单选或者复选列
            if(row_selection===false || row_selection === null){
                row_selection = false;
            }else if(row_selection == 'checkbox'){
                //设置类型未复选框
                rowSelection.type = 'checkbox';
            }else{
                //默认未单选
                row_selection = 'radio';
            }
            return <Table 
                    className="card-wrap page-table"
                    bordered 
                    {...this.props}
                    rowSelection={row_selection?rowSelection:null}
                    onRow={(record,index) => ({
                        onClick: ()=>{
                            if(!row_selection){
                                return;
                            }
                            this.onRowClick(record,index)
                        }
                      })}
                />
        };
        render = () => {
            return (
                <div>
                    {this.getOptions()}
                </div>
            )
        }
    }
  • order->index.js中:应用Eable组件实现

    import ETable from './../../components/ETable'
    
    <div className="content-wrap">
             <ETable
                    columns={columns}
                    updateSelectedItem={Utils.updateSelectedItem.bind(this)}
                    selectedRowKeys={this.state.selectedRowKeys}
                    //selectedIds={this.state.selectedIds}
                    selectedItem={this.state.selectedItem}
                    dataSource={this.state.list}
                    pagination={this.state.pagination}
              />
     </div>

注:项目来自慕课网

posted @ 2019-01-11 11:05  柳洁琼Elena  阅读(734)  评论(0编辑  收藏  举报