【共享單車】—— React後臺管理系統開發手記:項目工程化開發

前言:如下內容基於React全家桶+AntD實戰課程的學習實踐過程記錄。最終成果github地址:https://github.com/66Web/react-antd-manager,歡迎star。javascript


1、項目工程化概念 java

 

2、BaseForm的封裝react

城市管理中FilterForm子組件:ios

訂單管理中FilterForm子組件:git

員工管理中FilterForm子組件:github

【項目工程化】:表單封裝ajax

  • 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數據 axios

    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組件代碼:antd

    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)

 

3、列表數據請求封裝less

每一個管理模塊幾乎都有一個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)
    }

 

4、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>

注:項目來自慕課網

相關文章
相關標籤/搜索