【共享单车】—— 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"  />
                               <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>
            );
        }
    }  


注:项目来自慕课网

原文地址:https://www.cnblogs.com/ljq66/p/10222972.html

时间: 2024-10-07 19:17:54

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

【共享单车】—— React后台管理系统开发手记:主页面架构设计

前言:以下内容基于React全家桶+AntD实战课程的学习实践过程记录.最终成果github地址:https://github.com/66Web/react-antd-manager,欢迎star. 一.页面结构定义 左侧导航栏,右侧页面结构 右侧显示内容分别分为上Header.中Content和下Footer部分 二.目录结构定义 src->admin.js:项目主结构代码(index.js中替换App.js挂载到根节点) src->common.js:项目公共结构代码(类似admin.j

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

前言:以下内容基于React全家桶+AntD实战课程的学习实践过程记录.最终成果github地址:https://github.com/66Web/react-antd-manager,欢迎star. 一.项目概述       React全家桶 React基础知识.生命周期 Router 4.0 语法讲解 Redux集成开发      AnD UI组件 最实用基础组件 AntD栅格系统 ETable组件封装 BaseForm组件封装 表格内嵌单选.复选封装      公共机制封装 Axios请求

【共享单车】—— React后台管理系统开发手记:AntD Form基础组件

前言:以下内容基于React全家桶+AntD实战课程的学习实践过程记录.最终成果github地址:https://github.com/66Web/react-antd-manager,欢迎star. 一.使用Form组件开发登录页面 pages->form->login.js:对应路由/admin/form/login import React from 'react' import {Card, Form, Input, Button, message, Icon, Checkbox} f

【共享单车】—— React后台管理系统开发手记:Router 4.0路由实战演练

前言:以下内容基于React全家桶+AntD实战课程的学习实践过程记录.最终成果github地址:https://github.com/66Web/react-antd-manager,欢迎star. 一.React Router 4.0核心概念 4.0版本中已不需要路由配置,一切皆组件 react-router:基础路由包 提供了一些router的核心api,包括Router,Route,Switch等 react-router-dom:基于浏览器的路由(包含react-router) 提供了

【共享单车】—— React后台管理系统开发手记:UI菜单各个组件使用(Andt UI组件)

前言:以下内容基于React全家桶+AntD实战课程的学习实践过程记录.最终成果github地址:https://github.com/66Web/react-antd-manager,欢迎star. 一.按钮Button pages->ui->button.js:对应路由/admin/ui/buttons import React from 'react'; import {Card, Button, Radio} from 'antd' import './ui.less' class B

【共享单车】—— React后台管理系统开发手记:AntD Table高级表格

前言:以下内容基于React全家桶+AntD实战课程的学习实践过程记录.最终成果github地址:https://github.com/66Web/react-antd-manager,欢迎star. 一.头部固定 scroll属性:设置横向或纵向滚动,也可用于指定滚动区域的宽和高 <Card title="头部固定"> <Table bordered columns={columns} dataSource={this.state.dataSource} pagin

【共享单车】—— React后台管理系统开发手记:AntD Table基础表格

前言:以下内容基于React全家桶+AntD实战课程的学习实践过程记录.最终成果github地址:https://github.com/66Web/react-antd-manager,欢迎star. 一.基础表格 Table组件基础Api bordered属性:是否展示外边框和列边框 columns属性:表格列的配置描述(即表头) dataSource属性:数据数组 pagination属性:分页器,设为 false 时不展示和进行分页 <Card title="基础表格"&g

【共享单车】—— React后台管理系统开发手记:权限设置和菜单调整(未完)

前言:以下内容基于React全家桶+AntD实战课程的学习实践过程记录.最终成果github地址:https://github.com/66Web/react-antd-manager,欢迎star. 一.创建角色 权限菜单设计:RBAC权限模型(详解链接) RBAC,即基于角色的访问控制(Role-Based Access Control),是优秀的权限控制模型 主要通过角色和权限建立管理,再赋予用户不同的角色,来实现权限控制的目标 角色列表展示:对应Easy Mock数据接口/role/li

asp.net mvc+jquery easyui开发实战教程之网站后台管理系统开发2-Model层建立

上篇(asp.net mvc+jquery easyui开发实战教程之网站后台管理系统开发1-准备工作)文章讲解了开发过程中的准备工作,主要创建了项目数据库及项目,本文主要讲解项目M层的实现,M层这里讲的主要是通过Codefirst方式实现的. 一.M层简单介绍 1.M层很形象的将数据库里面的各个表格映射成了C#当中的类,比如上篇文章创建的用户表: ? 1 2 3 4 5 6 7 8 9 10 11 12 CREATE TABLE [dbo].[SYS_USER](          [ID]