【共享单车】—— React后台管理系统开发手记:城市管理和订单管理

时间:2022-10-23 15:33:45

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


一、城市管理

【共享单车】—— React后台管理系统开发手记:城市管理和订单管理

  • 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中

    【共享单车】—— React后台管理系统开发手记:城市管理和订单管理

  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);
    

      

二、订单管理

【共享单车】—— React后台管理系统开发手记:城市管理和订单管理

  •  顶部子组件:选择表单
    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);
    

      

三、订单详情

【共享单车】—— React后台管理系统开发手记:城市管理和订单管理

  • 跳转详情页
  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>
            );
        }
    }  

注:项目来自慕课网