1. 程式人生 > >【共享單車】—— React後臺管理系統開發手記:城市管理和訂單管理

【共享單車】—— React後臺管理系統開發手記:城市管理和訂單管理

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


一、城市管理

  • pages->city->index.js:對應路由/admin/city
  • 頂部子元件一:選擇表單
    class FilterForm extends React.Component{
    
        render(){
            const { getFieldDecorator } = this.props.form;
            return (
                <Form layout="inline">
                    <FormItem label="城市">
                        {
                            getFieldDecorator('city_id')(
                                <Select
                                    style={{width:100}}
                                    placeholder="全部"
                                >
                                    <Option value="">全部</Option>
                                    <Option value="1">北京市</Option>
                                    <Option value="2">天津市</Option>
                                    <Option value="3">深圳市</Option>
                                </Select>
                            )
                        }
                    </FormItem>
                    <FormItem label="用車模式">
                        {
                            getFieldDecorator('mode')(
                                <Select
                                    style={{ width: 120 }}
                                    placeholder="全部"
                                >
                                    <Option value="">全部</Option>
                                    <Option value="1">指定停車點模式</Option>
                                    <Option value="2">禁停區模式</Option>
                                </Select>
                            )
                        }
                    </FormItem>
                    <FormItem label="營運模式">
                        {
                            getFieldDecorator('op_mode')(
                                <Select
                                    style={{ width: 80 }}
                                    placeholder="全部"
                                >
                                    <Option value="">全部</Option>
                                    <Option value="1">自營</Option>
                                    <Option value="2">加盟</Option>
                                </Select>
                            )
                        }
                    </FormItem>
                    <FormItem label="加盟商授權狀態">
                        {
                            getFieldDecorator('auth_status')(
                                <Select
                                    style={{ width: 100 }}
                                    placeholder="全部"
                                >
                                    <Option value="">全部</Option>
                                    <Option value="1">已授權</Option>
                                    <Option value="2">未授權</Option>
                                </Select>
                            )
                        }
                    </FormItem>
                    <FormItem>
                        <Button type="primary" style={{margin:'0 20px'}}>查詢</Button>
                        <Button>重置</Button>
                    </FormItem>
                </Form>
            );
        }
    }
    FilterForm = Form.create({})(FilterForm);
  • 彈框子元件二:開通城市表單

    class OpenCityForm extends React.Component{
        render(){
            const formItemLayout = {
                labelCol:{   //label標籤佔據列數
                    span:5
                },
                wrapperCol:{ //Form表單佔據列數
                    span:19
                }
            }
            const { getFieldDecorator }  =this.props.form;
            return (
                <Form layout="horizontal">
                    <FormItem label="選擇城市" {...formItemLayout}>
                        {
                            getFieldDecorator('city_id',{
                                initialValue:'1'
                            })(
                                <Select style={{ width: 100 }}>
                                    <Option value="">全部</Option>
                                    <Option value="1">北京市</Option>
                                    <Option value="2">天津市</Option>
                                </Select>
                            )
                        }
                    </FormItem>
                    <FormItem label="營運模式" {...formItemLayout}>
                        {
                            getFieldDecorator('op_mode', {
                                initialValue: '1'
                            })(
                                <Select style={{ width: 100 }}>
                                    <Option value="1">自營</Option>
                                    <Option value="2">加盟</Option>
                                </Select>
                            )
                        }
                    </FormItem>
                    <FormItem label="用車模式" {...formItemLayout}>
                        {
                            getFieldDecorator('use_mode', {
                                initialValue: '1'
                            })(
                                <Select style={{ width: 100 }}>
                                    <Option value="1">指定停車點</Option>
                                    <Option value="2">禁停區</Option>
                                </Select>
                            )
                        }
                    </FormItem>
                </Form>
            );
        }
    }
    OpenCityForm = Form.create({})(OpenCityForm);
  • Easy Mock城市管理的資料介面:/open_city

    {
      "code": 0,
      "msg": "",
      "list": {
        "item_list|10": [{
          "id|+1": 1,
          "name": "@city",
          "mode|1-2": 1,
          "op_mode|1-2": 1,
          "franchisee_id": 77,
          "franchisee_name": "松果自營",
          "city_admins|1-2": [{
            "user_name": "@cname",
            "user_id|+1": 10001
          }],
          "open_time": "@datetime",
          "sys_user_name": "@cname",
          "update_time": 1546580667000
        }]
      },
      page: 1,
      page_size: 10,
      total: 20
    }
  1. componentDidMount()中:呼叫this.requestList(),預設請求介面資料
    componentDidMount(){
            this.requestList();
        }
    
    // 預設請求我們的介面資料
    requestList = ()=>{
            let _this = this;
            axios.ajax({
                url: '/open_city',
                data:{
                    params:{
                        page:this.params.page
                    }
                }
            }).then((res)=>{
                let list = res.list.item_list.map((item, index) => {
                    item.key = index;
                    return item;
                });
                this.setState({
                    list:list,
                    pagination:Utils.pagination(res,(current)=>{
                        _this.params.page = current;
                        _this.requestList();
                    })
                })
            })
    }  
  • Easy Mock城市開通的資料介面:/city/open

    {
      "code": 0,
      "list": "開通成功"
    }
    
  1. 【開通城市】按鈕:監聽onClick事件,呼叫this.handleOpenCity()顯示彈框

    state = {
        list:[],
        isShowOpenCity:false //預設隱藏彈框
    }
    
    // 開通城市
    handleOpenCity = ()=>{
        this.setState({
                isShowOpenCity:true
        })
    }
  2. Modal關鍵屬性visible控制彈框的顯示隱藏,關鍵事件onOk呼叫this.handleSubmit()提交表單資訊

     <Modal 
           title="開通城市"
           visible={this.state.isShowOpenCity}
           onCancel={()=>{
               this.setState({
                    isShowOpenCity:false
               })
           }}
           onOk={this.handleSubmit}
    >
           <OpenCityForm wrappedComponentRef={(inst)=>{this.cityForm = inst;}}/>
    </Modal>

    wrappedComponentRef屬性:拿到表單中的資訊物件inst,通過this.cityForm存到state中

  3. 城市開通訊息提交

    // 城市開通提交
    handleSubmit = ()=>{
            let cityInfo = this.cityForm.props.form.getFieldsValue();
            console.log(cityInfo);
            axios.ajax({
                url:'/city/open',
                data:{
                    params:cityInfo
                }
            }).then((res)=>{
                if(res.code === 0){
                    message.success('開通成功');
                    this.setState({
                        isShowOpenCity:false
                    })
                    this.requestList();
                }
            })
    }
    
  • 例項程式碼
    import React from 'react';
    import { Card, Button, Table, Form, Select, Modal, message } from 'antd';
    import axios from './../../axios/index';
    import Utils from './../../utils/utils';
    const FormItem = Form.Item;
    const Option = Select.Option;
    
    export default class City extends React.Component{
    
        state = {
            list:[],
            isShowOpenCity:false //預設隱藏彈框
        }
        params = {
            page:1
        }
        componentDidMount(){
            this.requestList();
        }
    
        // 預設請求我們的介面資料
        requestList = ()=>{
            let _this = this;
            axios.ajax({
                url: '/open_city',
                data:{
                    params:{
                        page:this.params.page
                    }
                }
            }).then((res)=>{
                let list = res.list.item_list.map((item, index) => {
                    item.key = index;
                    return item;
                });
                this.setState({
                    list:list,
                    pagination:Utils.pagination(res,(current)=>{
                        _this.params.page = current;
                        _this.requestList();
                    })
                })
            })
        }
    
        // 開通城市
        handleOpenCity = ()=>{
            this.setState({
                isShowOpenCity:true
            })
        }
        // 城市開通提交
        handleSubmit = ()=>{
            let cityInfo = this.cityForm.props.form.getFieldsValue();
            console.log(cityInfo);
            axios.ajax({
                url:'/city/open',
                data:{
                    params:cityInfo
                }
            }).then((res)=>{
                if(res.code === 0){
                    message.success('開通成功');
                    this.setState({
                        isShowOpenCity:false
                    })
                    this.requestList();
                }
            })
        }
        render(){
            const columns = [
                {
                    title:'城市ID',
                    dataIndex:'id'
                }, {
                    title: '城市名稱',
                    dataIndex: 'name'
                }, {
                    title: '用車模式',
                    dataIndex: 'mode',
                    render(mode){
                        return mode === 1 ?'停車點':'禁停區';
                    }
                }, {
                    title: '營運模式',
                    dataIndex: 'op_mode',
                    render(op_mode) {
                        return op_mode === 1 ? '自營' : '加盟';
                    }
                }, {
                    title: '授權加盟商',
                    dataIndex: 'franchisee_name'
                }, {
                    title: '城市管理員',
                    dataIndex: 'city_admins',
                    render(arr){  //處理陣列型別
                        return arr.map((item)=>{
                            return item.user_name;
                        }).join(',');
                    }
                }, {
                    title: '城市開通時間',
                    dataIndex: 'open_time'
                }, {
                    title: '操作時間',
                    dataIndex: 'update_time',
                    render: Utils.formateDate //格式化時間戳
                }, {
                    title: '操作人',
                    dataIndex: 'sys_user_name'
                }
            ]
            return (
                <div>
                    <Card>
                        <FilterForm />
                    </Card>
                    <Card style={{marginTop:10}}>
                        <Button type="primary" onClick={this.handleOpenCity}>開通城市</Button>
                    </Card>
                    <div className="content-wrap">
                        <Table
                            bordered
                            columns={columns}
                            dataSource={this.state.list}
                            pagination={this.state.pagination}
                        />
                    </div>
                    <Modal 
                        title="開通城市"
                        visible={this.state.isShowOpenCity}
                        onCancel={()=>{
                            this.setState({
                                isShowOpenCity:false
                            })
                        }}
                        onOk={this.handleSubmit}
                    >
                        <OpenCityForm wrappedComponentRef={(inst)=>{this.cityForm = inst;}}/>
                    </Modal>
                </div>
            );
        }
    }
    
    //子元件一:選擇表單
    class FilterForm extends React.Component{
    
        render(){
            const { getFieldDecorator } = this.props.form;
            return (
                <Form layout="inline">
                    <FormItem label="城市">
                        {
                            getFieldDecorator('city_id')(
                                <Select
                                    style={{width:100}}
                                    placeholder="全部"
                                >
                                    <Option value="">全部</Option>
                                    <Option value="1">北京市</Option>
                                    <Option value="2">天津市</Option>
                                    <Option value="3">深圳市</Option>
                                </Select>
                            )
                        }
                    </FormItem>
                    <FormItem label="用車模式">
                        {
                            getFieldDecorator('mode')(
                                <Select
                                    style={{ width: 120 }}
                                    placeholder="全部"
                                >
                                    <Option value="">全部</Option>
                                    <Option value="1">指定停車點模式</Option>
                                    <Option value="2">禁停區模式</Option>
                                </Select>
                            )
                        }
                    </FormItem>
                    <FormItem label="營運模式">
                        {
                            getFieldDecorator('op_mode')(
                                <Select
                                    style={{ width: 80 }}
                                    placeholder="全部"
                                >
                                    <Option value="">全部</Option>
                                    <Option value="1">自營</Option>
                                    <Option value="2">加盟</Option>
                                </Select>
                            )
                        }
                    </FormItem>
                    <FormItem label="加盟商授權狀態">
                        {
                            getFieldDecorator('auth_status')(
                                <Select
                                    style={{ width: 100 }}
                                    placeholder="全部"
                                >
                                    <Option value="">全部</Option>
                                    <Option value="1">已授權</Option>
                                    <Option value="2">未授權</Option>
                                </Select>
                            )
                        }
                    </FormItem>
                    <FormItem>
                        <Button type="primary" style={{margin:'0 20px'}}>查詢</Button>
                        <Button>重置</Button>
                    </FormItem>
                </Form>
            );
        }
    }
    FilterForm = Form.create({})(FilterForm);
    
    //子元件二:開通城市
    class OpenCityForm extends React.Component{
        render(){
            const formItemLayout = {
                labelCol:{   //label標籤佔據列數
                    span:5
                },
                wrapperCol:{ //Form表單佔據列數
                    span:19
                }
            }
            const { getFieldDecorator }  =this.props.form;
            return (
                <Form layout="horizontal">
                    <FormItem label="選擇城市" {...formItemLayout}>
                        {
                            getFieldDecorator('city_id',{
                                initialValue:'1'
                            })(
                                <Select style={{ width: 100 }}>
                                    <Option value="">全部</Option>
                                    <Option value="1">北京市</Option>
                                    <Option value="2">天津市</Option>
                                </Select>
                            )
                        }
                    </FormItem>
                    <FormItem label="營運模式" {...formItemLayout}>
                        {
                            getFieldDecorator('op_mode', {
                                initialValue: '1'
                            })(
                                <Select style={{ width: 100 }}>
                                    <Option value="1">自營</Option>
                                    <Option value="2">加盟</Option>
                                </Select>
                            )
                        }
                    </FormItem>
                    <FormItem label="用車模式" {...formItemLayout}>
                        {
                            getFieldDecorator('use_mode', {
                                initialValue: '1'
                            })(
                                <Select style={{ width: 100 }}>
                                    <Option value="1">指定停車點</Option>
                                    <Option value="2">禁停區</Option>
                                </Select>
                            )
                        }
                    </FormItem>
                </Form>
            );
        }
    }
    OpenCityForm = Form.create({})(OpenCityForm);
    

      

二、訂單管理

  •  頂部子元件:選擇表單
    class FilterForm extends React.Component{
    
        render(){
            const { getFieldDecorator } = this.props.form;
            return (
                <Form layout="inline">
                    <FormItem label="城市">
                        {
                            getFieldDecorator('city_id')(
                                <Select
                                    style={{width:100}}
                                    placeholder="全部"
                                >
                                    <Option value="">全部</Option>
                                    <Option value="1">北京市</Option>
                                    <Option value="2">天津市</Option>
                                    <Option value="3">深圳市</Option>
                                </Select>
                            )
                        }
                    </FormItem>
                    <FormItem label="訂單時間">
                        {
                            getFieldDecorator('start_time')(
                               <DatePicker showTime format="YYYY-MM-DD HH:mm:ss"/>
                            )
                        }
                    </FormItem>
                    <FormItem style={{marginLeft: -10}}>
                        {
                            getFieldDecorator('end_time')(
                               <DatePicker style={{marginLeft: 5}} showTime format="YYYY-MM-DD HH:mm:ss"/>
                            )
                        }
                    </FormItem>
                    <FormItem label="訂單狀態">
                        {
                            getFieldDecorator('status')(
                                <Select
                                    style={{ width: 80 }}
                                    placeholder="全部"
                                >
                                    <Option value="">全部</Option>
                                    <Option value="1">進行中</Option>
                                    <Option value="2">結束行程</Option>
                                </Select>
                            )
                        }
                    </FormItem>
                    <FormItem>
                        <Button type="primary" style={{margin:'0 5px'}}>查詢</Button>
                        <Button>重置</Button>
                    </FormItem>
                </Form>
            );
        }
    }
    FilterForm = Form.create({})(FilterForm);
  • Easy Mock訂單資料介面:/order/list
    {
      "code": 0,
      "msg": "",
      "list": {
        "item_list|10": [{
          "id": 2959165,
          "order_sn": /T180[0-9]{6}/,
          "bike_sn": "800116090",
          "user_id": 908352,
          "user_name": "@cname",
          "mobile": /1[0-9]{10}/,
          "distance": 2000,
          "total_time": 4000,
          "status|1-2": 1,
          "start_time": "@datetime",
          "end_time": "@datetime",
          "total_fee": 1000,
          "user_pay": 300
        }]
      },
      "page|1-9": 1,
      page_size: 10,
      total: 85,
      page_count: 9
    }
    

    同城市管理:呼叫this.requestList(),預設請求介面資料  

  • Easy Mock結束訂單資訊資料介面:/order/ebike_info
    {
      "code": 0,
      "list": {
        "id": 27296,
        "bike_sn": "800116116",
        "battery": 100,
        "start_time": "@datetime",
        "location": "西虹市海淀區桃花公園"
      }
    }
  • Easy Mock結束訂單成功資料介面:/order/finish_order

    {
      "code": 0,
      "list": "ok"
    }
  1. 【結束訂單】按鈕:監聽onClick事件,呼叫this.handleConfirm()顯示確認結束彈框

    <Button type="primary" style={{marginLeeft: 10}} onClick={this.handlConfirm}>結束訂單</Button>
    //訂單結束確認
    handleConfirm = () => {
            let item = this.state.selectedItem;
            if(!item){
                Modal.info({
                    title: '資訊',
                    content: '請選擇一條訂單進行結束'
                })
                return;
            }
            axios.ajax({
                url: '/order/ebike_info',
                data: {
                    params: {
                        orderId: item.id
                    }
                }
            }).then((res) => {
                if(res.code === 0 ){
                    this.setState({
                        orderInfo: res.list,
                        orderConfirmVisible: true
                    })
                }
           })
    }
  2. 確認取消:開啟Modal彈框,顯示要取消的訂單資訊

     <Modal 
            title="結束訂單"
            visible={this.state.orderConfirmVisible}
            onCancel={() => {
                 this.setState({
                       orderConfirmVisible: false
                 })
            }}
            onOk={this.handleFinishOrder}
            width={600}>
                  <Form layout="horizontal">
                        <FormItem label="車輛編號" {...formItemLayout}>
                                {this.state.orderInfo.bike_sn}
                        </FormItem>
                        <FormItem label="剩餘電量" {...formItemLayout}>
                                {this.state.orderInfo.battery + '%'}
                        </FormItem>
                        <FormItem label="行程開始時間" {...formItemLayout}>
                                {this.state.orderInfo.start_time}
                        </FormItem>
                        <FormItem label="當前位置" {...formItemLayout}>
                                {this.state.orderInfo.location}
                        </FormItem>               
                 </Form>
    </Modal> 
  3. 結束訂單:onOk事件呼叫this.handleFinishOrder()

    //結束訂單
    handleFinishOrder = () => {
            let item = this.state.selectedItem;
            axios.ajax({
                url: '/order/finish_order',
                data: {
                    params: {
                        orderId: item.id
                    }
                }
            }).then((res) => {
                if(res.code === 0){
                    message.success('訂單結束成功')
                    this.setState({
                        orderConfirmVisible: false
                    })
                    this.requestList();
                }
            })
    }
    
  • 例項程式碼:

    import React from 'react'
    import { Card, Button, Table, Form, Select, Modal, message, DatePicker } from 'antd';
    import axios from './../../axios/index';
    import Utils from './../../utils/utils';
    const FormItem = Form.Item;
    const Option = Select.Option;
    
    export default class Order extends React.Component{
    
        state = {
            orderInfo: {},
            orderConfirmVisible: false
        }
        params = {
            page:1
        }
        
        componentDidMount(){
            this.requestList();
        }
    
        requestList = () => {
            let _this = this;
            axios.ajax({
                url: '/order/list',
                data: {
                    params: {
                        page: this.params.page
                    }
                }
            }).then((res) => {
                if(res.code === 0){
                    let list = res.list.item_list.map((item, index) => {
                        item.key = index;
                        return item;
                    });
                    this.setState({
                        list:list,
                        selectedRowKeys: [],//重置
                        pagination:Utils.pagination(res,(current)=>{
                            _this.params.page = current;
                            _this.requestList();
                        })
                    })
                }
            })
        }
    
        //訂單結束確認
        handleConfirm = () => {
            let item = this.state.selectedItem;
            if(!item){
                Modal.info({
                    title: '資訊',
                    content: '請選擇一條訂單進行結束'
                })
                return;
            }
            axios.ajax({
                url: '/order/ebike_info',
                data: {
                    params: {
                        orderId: item.id
                    }
                }
            }).then((res) => {
                if(res.code === 0 ){
                    this.setState({
                        orderInfo: res.list,
                        orderConfirmVisible: true
                    })
                }
            })
        }
    
        //結束訂單
        handleFinishOrder = () => {
            let item = this.state.selectedItem;
            axios.ajax({
                url: '/order/finish_order',
                data: {
                    params: {
                        orderId: item.id
                    }
                }
            }).then((res) => {
                if(res.code === 0){
                    message.success('訂單結束成功')
                    this.setState({
                        orderConfirmVisible: false
                    })
                    this.requestList();
                }
            })
        }
        onRowClick = (record, index) => {
            let selectKey = [index];
            this.setState({
                selectedRowKeys: selectKey,
                selectedItem: record
            })
        }
    
        //訂單詳情頁
        openOrderDetail = () => {
            let item = this.state.selectedItem;
            if(!item){
                Modal.info({
                    title: '資訊',
                    content: '請先選擇一條訂單'
                })
                return;
            }
            window.open(`/#/common/order/detail/${item.id}`,'_blank')
        }
    
        render(){
            const columns = [
                {
                    title: '訂單編號',
                    dataIndex: 'order_sn'
                },
                {
                    title: '車輛編號',
                    dataIndex: 'bike_sn'
                },
                {
                    title: '使用者名稱',
                    dataIndex: 'user_name'
                },
                {
                    title: '手機號',
                    dataIndex: 'mobile'
                },
                {
                    title: '里程',
                    dataIndex: 'distance',
                    render(distance){
                        return distance/1000 + 'Km';
                    }
                },
                {
                    title: '行駛時長',
                    dataIndex: 'total_time'
                },
                {
                    title: '狀態',
                    dataIndex: 'status'
                },
                {
                    title: '開始時間',
                    dataIndex: 'start_time'
                },
                {
                    title: '結束時間',
                    dataIndex: 'end_time'
                },
                {
                    title: '訂單金額',
                    dataIndex: 'total_fee'
                },
                {
                    title: '實付金額',
                    dataIndex: 'user_pay'
                }
            ]
            const formItemLayout = {
                labelCol: {
                    span: 5
                },
                wrapperCol: {
                    span: 19
                }
            }
            const selectedRowKeys = this.state.selectedRowKeys;
            const rowSelection = {
                type: 'radio',
                selectedRowKeys
            }
    
            return (
                <div>
                    <Card>
                        <FilterForm />
                    </Card>
                    <Card style={{marginTop:10}}>
                        <Button type="primary" onClick={this.openOrderDetail}>訂單詳情</Button>
                        <Button type="primary" style={{marginLeeft: 10}} onClick={this.handlConfirm}>結束訂單</Button>
                    </Card>
                    <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>
                    <Modal 
                        title="結束訂單"
                        visible={this.state.orderConfirmVisible}
                        onCancel={() => {
                            this.setState({
                                orderConfirmVisible: false
                            })
                        }}
                        onOk={this.handleFinishOrder}
                        width={600}>
                        <Form layout="horizontal">
                            <FormItem label="車輛編號" {...formItemLayout}>
                                {this.state.orderInfo.bike_sn}
                            </FormItem>
                            <FormItem label="剩餘電量" {...formItemLayout}>
                                {this.state.orderInfo.battery + '%'}
                            </FormItem>
                            <FormItem label="行程開始時間" {...formItemLayout}>
                                {this.state.orderInfo.start_time}
                            </FormItem>
                            <FormItem label="當前位置" {...formItemLayout}>
                                {this.state.orderInfo.location}
                            </FormItem>               
                        </Form>
                    </Modal> 
                </div>
            )
        }
    }
    
    //子元件一:選擇表單
    class FilterForm extends React.Component{
    
        render(){
            const { getFieldDecorator } = this.props.form;
            return (
                <Form layout="inline">
                    <FormItem label="城市">
                        {
                            getFieldDecorator('city_id')(
                                <Select
                                    style={{width:100}}
                                    placeholder="全部"
                                >
                                    <Option value="">全部</Option>
                                    <Option value="1">北京市</Option>
                                    <Option value="2">天津市</Option>
                                    <Option value="3">深圳市</Option>
                                </Select>
                            )
                        }
                    </FormItem>
                    <FormItem label="訂單時間">
                        {
                            getFieldDecorator('start_time')(
                               <DatePicker showTime format="YYYY-MM-DD HH:mm:ss"/>
                            )
                        }
                    </FormItem>
                    <FormItem style={{marginLeft: -10}}>
                        {
                            getFieldDecorator('end_time')(
                               <DatePicker style={{marginLeft: 5}} showTime format="YYYY-MM-DD HH:mm:ss"/>
                            )
                        }
                    </FormItem>
                    <FormItem label="訂單狀態">
                        {
                            getFieldDecorator('status')(
                                <Select
                                    style={{ width: 80 }}
                                    placeholder="全部"
                                >
                                    <Option value="">全部</Option>
                                    <Option value="1">進行中</Option>
                                    <Option value="2">結束行程</Option>
                                </Select>
                            )
                        }
                    </FormItem>
                    <FormItem>
                        <Button type="primary" style={{margin:'0 5px'}}>查詢</Button>
                        <Button>重置</Button>
                    </FormItem>
                </Form>
            );
        }
    }
    FilterForm = Form.create({})(FilterForm);
    

      

三、訂單詳情

  • 跳轉詳情頁
  1. pages->order->index.js中:【訂單詳情】按鈕監聽onClick事件,呼叫this.openOrderDetail(),跳轉路由
     //訂單詳情頁
    openOrderDetail = () => {
            let item = this.state.selectedItem;
            if(!item){
                Modal.info({
                    title: '資訊',
                    content: '請先選擇一條訂單'
                })
                return;
            }
            window.open(`/#/common/order/detail/${item.id}`,'_blank')
    }
    

    關鍵:window.open(`/#/common/order/detail/${item.id}`,'_blank')

  2. src目錄下:新建common.js,類似admin.js編寫專案公共結構程式碼,負責路由詳情頁展示

    import React from 'react'
    import { Row, Col } from 'antd';
    import Header from './components/Header'
    import './style/common.less'
    
    export default class Common extends React.Component {
    
        render() {
            return (
                <div>
                    <Row className="simple-page">
                        <Header menuType="second"/>
                    </Row>
                    <Row className="content">
                        {this.props.children}
                    </Row>
                </div>
            );
        }
    }
    

    通過menuType:控制顯示header元件的不同樣式(components->header->index.js

    //其它程式碼
    render() {
            const menuType = this.props.menuType;
            return (
                <div className="header">
                   <Row className="header-top">
                      {
                          menuType ? 
                          <Col span="6" className="logo">
                               <img src="/assets/logo-ant.svg" alt="" />
                               <span>LJQ 通用管理系統</span>
                          </Col> : ''
                      }
                      <Col span={menuType ? 18 : 24}>
                          <span>歡迎,{this.state.userName}</span>
                          <a href='#'>退出</a>
                      </Col>
                   </Row>
                   {
                       menuType ? '' : 
                       <Row className="breadcrumb">
                            <Col span={4} className="breadcrumb-title">
                                首頁
                            </Col>
                            <Col span={20} className="weather">
                                <span className="date">{this.state.sysTime}</span>
                                <span className="weather-detail">晴轉多雲</span>
                            </Col>
                       </Row>
                   }
                </div>
            )
    }
    

    CSS樣式:

    //style->common.less
    ul,li{
        list-style: none;
    }
    .clearfix{
        &::after{
            content:'';
            clear: both;
            display: block;
            visibility: hidden;
        }
    }
    .content{
        padding: 20px
    }
    
    //components->header->index.less
    //.common 頁面簡單頭
    .simple-page{
        .header-top{
            background: #1890ff;
            color: @colorM;
        }
        .ant-form, .ant-col-12, .weather{
            display: none;
        }
    }
    
    //引入pages->order->detail.less
  3. router.js中:引入Common元件,使用<Route />的render方法定義巢狀路由

    <Route path="/common" render={() => 
           <Common>
                 <Route path="/common/order/detail/:orderId" component={OrderDetail} />
           </Common> 
    }/> 
    
  • 獲取訂單詳情基礎資訊

  1. Easy Mock訂單詳情資料介面:/order/detail 

    {
      "code": 0,
      "msg": "",
      "list": {
        "status": 2,
        "order_sn": "T1803244422704080JGJI",
        "bike_sn": '802410001',
        "mode|1-2": 1,
        "start_location": "北京市昌平區回龍觀東大街",
        "end_location": "北京市海淀區奧林匹克公園",
        "city_id": 1,
        "mobile": "13597482075",
        "user_name": "@cname",
        "distance": 10000,
        "bike_gps": "116.398806,40.008637",
        "start_time": 1546580667000,
        "end_time": 1546608995000,
        "total_time": 224,
        "position_list": [{
            "lon": 116.361221,
            "lat": 40.043776
          },
          {
            "lon": 116.363736,
            "lat": 40.038086
          },
          {
            "lon": 116.364599,
            "lat": 40.036484
          },
          {
            "lon": 116.373438,
            "lat": 40.03538
          },
          {
            "lon": 116.377966,
            "lat": 40.036263
          },
          {
            "lon": 116.379762,
            "lat": 40.03654
          },
          {
            "lon": 116.38084,
            "lat": 40.033225
          },
          {
            "lon": 116.38084,
            "lat": 40.029413
          },
          {
            "lon": 116.381343,
            "lat": 40.021291
          },
          {
            "lon": 116.381846,
            "lat": 40.015821
          },
          {
            "lon": 116.382637,
            "lat": 40.008084
          },
          {
            "lon": 116.398806,
            "lat": 40.008637
          }
        ],
        "area": [{
            "lon": "116.274737",
            "lat": "40.139759",
            "ts": null
          },
          {
            "lon": "116.316562",
            "lat": "40.144943",
            "ts": null
          },
          {
            "lon": "116.351631",
            "lat": "40.129498",
            "ts": null
          },
          {
            "lon": "116.390582",
            "lat": "40.082481",
            "ts": null
          },
          {
            "lon": "116.38742",
            "lat": "40.01065",
            "ts": null
          },
          {
            "lon": "116.414297",
            "lat": "40.01181",
            "ts": null
          },
          {
            "lon": "116.696242",
            "lat": "39.964035",
            "ts": null
          },
          {
            "lon": "116.494498",
            "lat": "39.851306",
            "ts": null
          },
          {
            "lon": "116.238086",
            "lat": "39.848647",
            "ts": null
          },
          {
            "lon": "116.189454",
            "lat": "39.999418",
            "ts": null
          },
          {
            "lon": "116.244646",
            "lat": "39.990574",
            "ts": null
          },
          {
            "lon": "116.281441",
            "lat": "40.008703",
            "ts": null
          },
          {
            "lon": "116.271092",
            "lat": "40.142201",
            "ts": null
          },
          {
            "lon": "116.271092",
            "lat": "40.142201",
            "ts": null
          }
        ],
        "area_list": null,
        "npl_list": [{
          "id": 8265,
          "name": "北辰世紀中心-a座",
          "city_id": 1,
          "type": 3,
          "status": 0,
          "map_point": "116.39338796444|40.008120315215;116.39494038009002|40.008177258745;116.39496911688|40.006268094213;116.39512457763|40.004256795877;116.39360214742|40.004222412241;116.39357190147|40.005075745782;116.39351397873|40.005836165232;116.39338796444|40.008120315215",
          "map_point_array": [
            "116.39338796444|40.008120315215",
            "116.396053|40.008273",
            "116.396448|40.006338",
            "116.396915|40.004266",
            "116.39192|40.004072",
            "116.391525|40.004984",
            "116.391381|40.005924",
            "116.391166|40.007913"
          ],
          "map_status": 1,
          "creator_name": "趙程程",
          "create_time": 1507863539000
        }]
      }
    }
  2. componentDidMount()中獲取url引數orderId:呼叫this.getDetailInfo(orderId)獲取訂單詳情資料

    componentDidMount(){
            let orderId = this.props.match.params.orderId;
            if(orderId){
               this.getDetailInfo(orderId);
            }
    }
    
    getDetailInfo = (orderId) => {
            axios.ajax({
                url: '/order/detail',
                data: {
                    params: {
                        orderId: orderId
                    }
                }
            }).then((res) => {
                if(res.code === 0){
                    this.setState({
                        orderInfo: res.list
                    })
                    this.renderMap(res.list);
                }
            })
    }
    

    關鍵:this.props.match.params.引數 詳情:【React獲取url引數—this.props.match

  • 例項程式碼

    import React from 'react';
    import { Card } from 'antd';
    import axios from '../../axios';
    import './detail.less';
    
    export default class Order extends React.Component{
    
        state = {}
    
        componentDidMount(){
            let orderId = this.props.match.params.orderId;
            if(orderId){
               this.getDetailInfo(orderId);
            }
        }
    
        getDetailInfo = (orderId) => {
            axios.ajax({
                url: '/order/detail',
                data: {
                    params: {
                        orderId: orderId
                    }
                }
            }).then((res) => {
                if(res.code === 0){
                    this.setState({
                        orderInfo: res.list
                    })
                    this.renderMap(res.list);
                }
            })
        }
    
        //初始化地圖
        renderMap = (list) => {
            this.map = new window.BMap.Map('orderDetailMap');
            // this.map.centerAndZoom('北京', 11)
            //新增地圖控制元件
            this.addMapControl();
            //呼叫路線圖繪製方法
            this.drawBikeRoute(list.position_list);
            //呼叫服務區繪製方法
            this.drawServiceArea(list.area);
        }
    
        //新增地圖控制元件
        addMapControl = () => {
            let map = this.map;
            map.addControl(new window.BMap.ScaleControl({ anchor: window.BMAP_ANCHOR_TOP_RIGHT }));
            map.addControl(new window.BMap.NavigationControl({ anchor: window.BMAP_ANCHOR_TOP_RIGHT }));
        }
    
        //繪製使用者行駛路線圖
        drawBikeRoute = (positionList) => {
            let map = this.map;
            let startPoint = '';
            let endPoint = '';
            if(positionList.length > 0){
               //起點
               let first = positionList[0]; 
               startPoint = new window.BMap.Point(first.lon, first.lat);
               let startIcon = new window.BMap.Icon('/assets/start_point.png', new window.BMap.Size(36,42),{
                   imageSize: new window.BMap.Size(36,42),
                   anchor: new window.BMap.Size(36,42)
               })
    
               let startMarker = new window.BMap.Marker(startPoint, {icon: startIcon});
               this.map.addOverlay(startMarker);
    
               //終點
               let last = positionList[positionList.length-1]; 
               endPoint = new window.BMap.Point(last.lon, last.lat);
               let endIcon = new window.BMap.Icon('/assets/end_point.png', new window.BMap.Size(36,42),{
                   imageSize: new window.BMap.Size(36,42),
                   anchor: new window.BMap.Size(36,42)
               })
               let endMarker = new window.BMap.Marker(endPoint, {icon: endIcon});
               this.map.addOverlay(endMarker);
              
               //連線路線圖
               let trackPoint = [];
               for(let i=0; i<positionList.length; i++){
                   let point = positionList[i]
                   trackPoint.push(new window.BMap.Point(point.lon, point.lat))
               }
    
               let polyline = new window.BMap.Polyline(trackPoint, {
                   strokeColor: '#1869AD',
                   strokeWeight: 3,
                   strokeOpacity: 1
               })
               this.map.addOverlay(polyline);
    
               //設定地圖中心點
               this.map.centerAndZoom(endPoint, 11)
            }
        }   
    
        //繪製服務區
        drawServiceArea = (positionList) => {
            let trackPoint = [];
            for(let i=0; i<positionList.length; i++){
                   let point = positionList[i]
                   trackPoint.push(new window.BMap.Point(point.lon, point.lat))
            }
    
            let polygon = new window.BMap.Polygon(trackPoint, {
                strokeColor: '#CE0000',
                strokeWeight: 4,
                strokeOpacity: 1,
                fillColor: '#ff8605',
                fillOpacity: 0.4
            }) 
            this.map.addOverlay(polygon);
        } 
    
        render(){
            const info = this.state.orderInfo || {};
            return (
               <div>
                   <Card>
                       <div id="orderDetailMap" className="order-map"></div>
                       <div className="detail-items">
                            <div className="item-title">基礎資訊</div>
                            <ul className="detail-form">
                                <li>
                                    <div className="detail-form-left">用車模式</div>
                                    <div className="detail-form-content">{info.mode === 1 ? '伺服器' : '停車點'}</div>
                                </li>
                                <li>
                                    <div className="detail-form-left">訂單編號</div>
                                    <div className="detail-form-content">{info.order_sn}</div>
                                </li>
                                <li>
                                    <div className="detail-form-left">車輛編號</div>
                                    <div className="detail-form-content">{info.bike_sn}</div>
                                </li>
                                <li>
                                    <div className="detail-form-left">使用者姓名</div>
                                    <div className="detail-form-content">{info.user_name}</div>
                                </li>
                                <li>
                                    <div className="detail-form-left">手機號碼</div>
                                    <div className="detail-form-content">{info.mobile}</div>
                                </li>
                            </ul>
                       </div>
                       <div className="detail-items">
                            <div className="item-title">行駛軌跡</div>
                            <ul className="detail-form">
                                <li>
                                    <div className="detail-form-left">行駛起點</div>
                                    <div className="detail-form-content">{info.start_location}</div>
                                </li>
                                <li>
                                    <div className="detail-form-left">行駛終點</div>
                                    <div className="detail-form-content">{info.end_location}</div>
                                </li>
                                <li>
                                    <div className="detail-form-left">行駛里程</div>
                                    <div className="detail-form-content">{info.distance/1000}Km</div>
                                </li>
                            </ul>
                       </div>
                   </Card>
               </div>
            );
        }
    }  

注:專案來自慕課網