(记录笔记8)——8.2 订单管理

本文详细介绍了订单管理系统的实现,包括订单数据接口、订单状态管理、订单结束流程,以及如何利用百度地图API进行订单详情地图可视化,展示了从基础页面构建到地图控件、路线绘制和服务区展示的全过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

订单管理

Github订单管理


一 基础页面

Github

1.1 顶部子组件:选择表单

//子组件一:选择表单
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
                placeholder="请选择开始时间"
                showTime
                format="YYYY-MM-DD HH:mm:ss"
              />
            )
          }
        </FormItem>

        <FormItem>
          {
            getFieldDecorator('end_time')(
              <DatePicker
                placeholder="请选择结束时间"
                showTime
                format="YYYY-MM-DD HH:mm:ss"
              />
            )
          }
        </FormItem>


        <FormItem label="订单状态">
          {
            getFieldDecorator('order_status')(
              <Select
                style={{width: 150}}
                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);

1.2 数据接口

1. 订单数据接口

/order/list

{
  "code": 0,
  "msg": "",
  "result": {
    "page|1-9": 1,
    "page_size": 10,
    "total": 85,
    "page_count": 9,
    "item_list|10": [{
      "id|+1": 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
    }]
  },
}

同城市管理:调用this.requestList(),默认请求接口数据

2. 结束订单接口

/order/ebike_info

{
  "code": '0',
  "result": {
    "id": 27296,
    "bike_sn": "800116116",
    "battery": 100,
    "start_time": "@datetime",
    "location": "北京市海淀区奥林匹克公园"
  }
}
3. 结束成功接口

/order/finish_order

{
  "code": '0',
  "result": 'Ok'
}

1.3 实例代码

1. 结束订单按钮

监听onClick事件,调用this.handleConfirm()显示确认结束弹框

 >  >  > <Button type="primary" style={{marginLeeft: 10}} onClick={this.handlConfirm}>结束订单</Button>
 >    
 >      
 >     ```javascript
 >        // 订单结束确认
 >        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.result,
 >                  orderConfirmVisble: true,
 >                });
 >              }
 >            }
 >          );
 >        };
 >      ```
 >    ```
 >  ```
 > ```
2. 确认取消

打开Modal弹框,显示要取消的订单信息

 <Modal
          title="结束订单"
          visible={this.state.orderConfirmVisble}
          onCancel={() => {
            this.setState({
              orderConfirmVisble: false
            });
          }}
          onOk={this.handleFinishOrder}
          width={600}
        >
          <OpenCityForm {...this.state.orderInfo} />
   </Modal>

...

class OpenCityForm extends React.Component {
  render() {
      return (...)
 }
OpenCityForm = Form.create({})(OpenCityForm);
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({
          orderConfirmVisble: false
        });
        this.requestList();
      }
    });
  };
// src/pages/order/index.js
import React from 'react';
import {Card, Table, Form, Modal, Button, message, Input, Icon, Select, 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:{},
    orderConfirmVisble: false
  };

  params = {
    page: 1
  };

  componentDidMount() {
    this.requestList();
  }

  // 默认请求我们的接口数据
  requestList = () => {
    let _this = this;
    axios.ajax({
      url: '/order/list',
      data: {
        params: {
          page: this.params.page
        }
      }
    }).then((res) => {
      let list = res.result.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();
        })
      });
    });
  };

  // 订单结束确认
  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.result,
            orderConfirmVisble: 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({
          orderConfirmVisble: false
        });
        this.requestList();
      }
    });
  };

  onRowClick = (record, index) => {
    let selectKey = [index];
    this.setState({
      selectedRowKeys: selectKey,
      selectedItem: record
    });
  };

  onSelectChange = (selectedRowKeys, selectedItem) => {
    const record = selectedItem[0];
    this.setState({
      selectedRowKeys: selectedRowKeys,
      selectedItem: record
    });
  };

  render() {
    const selectedRowKeys = this.state.selectedRowKeys;

    const rowSelection = {
      type: 'radio',
      selectedRowKeys,
      onChange: this.onSelectChange
    };


    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',
      render(status) {
        return status == 1 ? '进行中' : '行程结束';
      }
    }, {
      title: '开始时间',
      dataIndex: 'start_time'
    }, {
      title: '结束时间',
      dataIndex: 'end_time'
    }, {
      title: '订单金额',
      dataIndex: 'total_fee'
    }, {
      title: '实付金额',
      dataIndex: 'user_pay'
    }];

    //{...this.state.orderInfo}
    // 这个用法 相当于 从state 中取出 orderInfo 这个对象, 然后将其(this.state.orderInfo)展开
    // 在子组件 ,使用props进行解构


    /*
    * var a = {b:[{id: 27296, bike_sn: "800116116"},{name:"张三"}]}
    * console.log(a.b) // => [0:{id: 27296, bike_sn: "800116116"},
    *                         1:{name:"张三"}
    *                        ]
    *
    * console.log(...a.b) // {id: 27296, bike_sn: "800116116"}
    *                        {name:"张三"}
    */
    return (
      <div>
        <Card>
          <FilterForm/>
        </Card>

        <Card style={{marginTop: 10}}>
          <Button type="primary">订单详情</Button>
          <Button type="primary" style={{marginLeft: 20}} onClick={this.handleConfirm}>结束详情</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.orderConfirmVisble}
          onCancel={() => {
            this.setState({
              orderConfirmVisble: false
            });
          }}
          onOk={this.handleFinishOrder}
          width={600}
        >
          <OpenCityForm {...this.state.orderInfo} />
        </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
                placeholder="请选择开始时间"
                showTime
                format="YYYY-MM-DD HH:mm:ss"
              />
            )
          }
        </FormItem>

        <FormItem>
          {
            getFieldDecorator('end_time')(
              <DatePicker
                placeholder="请选择结束时间"
                showTime
                format="YYYY-MM-DD HH:mm:ss"
              />
            )
          }
        </FormItem>


        <FormItem label="订单状态">
          {
            getFieldDecorator('order_status')(
              <Select
                style={{width: 150}}
                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() {
    // console.log(this.props); // => {form: {…}, id: 27296, bike_sn: "800116116", battery: 100, start_time: "1972-07-26 03:08:22", …}
    const {bike_sn, battery,start_time,location} = this.props;
    const formItemLayout = {
      labelCol: {
        span: 5
      },
      wrapperCol: {
        span: 19
      }
    };

    return (
      <Form>
        <FormItem label="车辆编号" {...formItemLayout}>
          {bike_sn}
        </FormItem>
        <FormItem label="剩余电量" {...formItemLayout}>
          {battery + "%"}
        </FormItem>
        <FormItem label="行程开始时间" {...formItemLayout}>
          {start_time}
        </FormItem>
        <FormItem label="当前位置" {...formItemLayout}>
          {location}
        </FormItem>
      </Form>
    );
  }
}

OpenCityForm = Form.create({})(OpenCityForm);

二 订单详情(基础信息)

2.1 跳转详情页

Github地址

1. 订单详情

按钮监听onClick事件

pages->order->index.js中:【订单详情】按钮监听onClick事件,调用this.openOrderDetail(),跳转路由

  // 订单详情页
  openOrderDetail = () => {
    let item = this.state.selectedItem;
    if (!item) {
      Modal.info({
        title: '信息',
        content: '请先选择一条订单'
      });
      return;
    }
    // 通过window.open 进行路由的跳转
    window.open('/#/common/order/detail/' + item.id,'_blank')
  };

关键:window.open('/#/common/order/detail/' + item.id,'_blank')

2. 编写公共代码

src目录下:新建common.js,类似admin.js编写项目公共结构代码,负责路由详情页展示

// src/common.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)

3. 实例代码
// src/components/Header/index.js
import React from 'react';
/*
Header组件 分两部分建立两行Row
第一行是用户的个人信息(这里以后要通过变量传输进来)
* */
import {Row, Col} from "antd";
import './index.less'
import Util from '../../utils/utils'//导入公共机制
import axios from "../../axios";//引入axios组件

export default class Header extends React.Component {
    ...
    render() {
        // 取出menuType 用作二级导航(父组件Common.js传来)
        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>IMooc 通用管理系统</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-img">
                            <img src={this.state.dayPictureUrl} alt=""/>
                        </span>
                            <span className="weather-detail">
                            {this.state.weather}
                                {/*{this.state.date}*/}
                        </span>
                        </Col>
                    </Row>
                }
            </div>
        );
    }
}
4. 相关CSS样式

CSS样式

// src/components/Header/index.less
@import "./../../style/default.less";
.header {
  background-color:@colorM ;
  .header-top {
    height: 60px;
    line-height: 60px;
    padding: 0 20px;
    text-align: right;
    .logo{
      line-height: 60px;
      text-align: left;
      font-size: 18px;
      img{
        height: 40px;
        vertical-align: middle;
      }
      span{
        margin-left: 5px;
      }
    };
    a {
      margin-left: 40px;
    }
  }
  .breadcrumb {
    height: 40px;
    line-height: 40px;
    text-align: right;
    padding: 0 20px;
    border-top: 1px solid #f9c700;
    .breadcrumb-title {
      text-align: center;
      font-size: @fontC;
      &:after{
        position: absolute;
        content: '';
        left: 83px;
        top: 39px;
        border-top: 9px solid @colorM;
        border-left: 12px solid transparent;
        border-right: 12px solid transparent;
      }
    }
    .weather {
      text-align: right;
      font-size: 14px;
      .date {
        margin-right: 10px;
        vertical-align: middle;
      }
      .weather-img{
        img{
          height: 15px;
        }
      }
      .weather-detail{
        margin-left: 5px;
        vertical-align: middle;
      }

    }
  }
}

// common 页面简单头
.simple-page{
  .header-top{
    background:#1890ff;
    color:@colorM;
  }
}

//引入pages->order->detail.less
5. router 组件

router.js中:引入Common组件,使用的render方法定义嵌套路由

<Route path="/common" render={() => {
    return <Common>
        <Route path="/common/order/detail/:orderId" component={Login}/>
            </Common>
	}}
/>

2.2 订单详情基础信息

获取订单详情基础信息

Github地址

1. 订单详情数据接口

/order/detail

{
  "code": '0',
  "msg": '',
  "result": {
    "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": 1521865027000,
    "end_time": 1521865251000,
    "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. 获取url参数orderId

componentDidMount()中获取url参数orderId:调用this.getDetailInfo(orderId)获取订单详情数据

 componentDidMount() {
    // 通过this.props.match.params.     取路由中的id(router-v4)
    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.result,
        });
      }
    });
  };

关键:this.props.match.params.参数 详情:React获取url参数—this.props.match

3. 实例代码
// src/pages/order/detail.js
import React from 'react';
import {Card} from 'antd';
import axios from './../../axios/index';
import './detail.less';

export default class OrderDetail extends React.Component {

  state = {};

  componentDidMount() {
    // 通过this.props.match.params.     取路由中的id(router-v4)
    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.result,
        });
      }
    });
  };

  render() {
    const info = this.state.orderInfo || {};//如果orderInfo 为空,返回 {}
    return (
      <div>
        <Card>
          <div id="OrderDetailMap"></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}公里</div>
              </li>
            </ul>
          </div>
        </Card>
      </div>
    );
  }
}

三 订单详情(地图)

具体使用查看百度地图api网址:http://lbsyun.baidu.com/index.php?title=jspopular/guide/widget

地图实现步骤

  • 创建ak(account key) , 加载百度地图sdk
  • 地图初始化
  • 添加地图控件
  • 绘制用户行驶路线
  • 绘制服务区地图

0. 代码格式

// src/pages/order/detail.js
import React from 'react';
import {Card} from 'antd';
import axios from './../../axios/index';
import './detail.less';

export default class OrderDetail extends React.Component {

  state = {};

  componentDidMount() {...}

  getDetailInfo = (orderId) => {...};

  // 初始化地图
  renderMap = (result) => {
    this.map = new window.BMap.Map('orderDetailMap');
    // 添加地图控件
    this.addMapControl();
    // 调用路线图绘制方法
    this.drawBikeRoute(result.position_list); 
    // 调用服务区绘制方法
    this.drawServiceArea(result.area);
  };

  // 添加地图控件
  addMapControl = () => {...};

  // 绘制用户的行驶路线
  // 需要坐标点(positionList)做参数
  drawBikeRoute = (positionList) => {...}


  // 绘制服务区
  drawServiceArea = (positionList) => {...};

  render() {
    const info = this.state.orderInfo || {};//如果orderInfo 为空,返回 {}
    return (
      <div>
        ...
      </div>
    );
  }
}

1. 创建ak

获取到Ak 值后就可以调用百度地图的服务了?



引入模块: 当没有npm 包时,需要使用src 引入script标签这样(如:引入 bootstrap…等)

拷贝src链接 到public目录下

<script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=您的密钥"/>

注: 在引入第三方模块时,常遇到,变量定义找不到

这时,使用 window. 变量名 , 使变量绑定到全局变量即可解决

react 是单页面程序

<!DOCTYPE html>
<html lang="en">
<!--public/index.html-->
  <head>
   ...
    <title>React App</title>
    <!--通过script 标签引入外部模块-->
    <script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=XmWWWzyDp7KbVdtcGKgDqAc8XKgTxGIG"/>
  </head>
  <body>
   ...
  </body>
</html>

2. 地图初始化

  // 初始化地图
  renderMap = ()=>{
    this.map = new window.BMap.Map('orderDetailMap');//new BMap.Map('orderDetailMap',,{enableMapClick:false});地图无法点击
    this.map.centerAndZoom('北京',11);
    this.addMapControl();
  };

3. 地图控件

 // 添加地图控件
  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}))
  };
控件类名简介
抽象基类Control所有控件均继承此类的方法、属性。通过此类您可实现自定义控件
平移缩放控件NavigationControlPC端默认位于地图左上方,它包含控制地图的平移和缩放的功能。移动端提供缩放控件,默认位于地图右下方
缩略地图OverviewMapControl默认位于地图右下方,是一个可折叠的缩略地图
比例尺ScaleControl默认位于地图左下方,显示地图的比例关系
地图类型MapTypeControl默认位于地图右上方
版权CopyrightControl默认位于地图左下方
定位GeolocationControl针对移动端开发,默认位于地图左下方

控制控件位置

初始化控件时,可提供一个可选参数,其中的anchor和offset属性共同控制控件在地图上的位置。 anchor表示控件的停靠位置,即控件停靠在地图的哪个角。当地图尺寸发生变化时,控件会根据停靠位置的不同来调整自己的位置。

anchor值位置说明
BMAP_ANCHOR_TOP_LEFT表示控件定位于地图的左上角
BMAP_ANCHOR_TOP_RIGHT表示控件定位于地图的右上角
BMAP_ANCHOR_BOTTOM_LEFT表示控件定位于地图的左下角
BMAP_ANCHOR_BOTTOM_RIGHT表示控件定位于地图的右下角

控件位置偏移

offset

4. 行驶路线

  1. 绘制 起/终 坐标点
  2. 将 起点/终点 用折线进行连接
  // 绘制用户的行驶路线
  // 需要坐标点(positionList)做参数
  drawBikeRoute = (positionList) => {
    let map = this.map; // 通过map 拿到地图的对象
    let startPoint = '';
    let endPoint = '';
    if (positionList.length > 0) {
      let first = positionList[0]; // 第一个坐标点
      let last = positionList[positionList.length - 1]; // 第一个坐标点
      startPoint = new window.BMap.Point(first.lon, first.lat); // arr.lon 经度 arr.lat 纬度

      // 创建起始坐标点的图标(Icon),设置Icon图标的大小(宽:36,高:42)
      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)
      });


      // 创建标注
      // 定义Marker 将图标放入页面(坐标点,图标)
      let startMarker = new window.BMap.Marker(startPoint, {icon: startIcon});

      // 将标注添加到地图中
      this.map.addOverlay(startMarker);


      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++) {
        // 换了个名称,用point 代替positionList 显得简洁
        let point = positionList[i];
        // 将接口返回的坐标点,转换为百度地图api 需要的坐标点
        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);
    }
  };

5. 绘制服务区

// 绘制服务区
  drawServiceArea = (positionList) => {
    // 连接路线图
    let trackPoint = [];
    for (let i = 0; i < positionList.length; i++) {
      // 换了个名称,用point 代替positionList 显得简洁
      let point = positionList[i];
      // 将接口返回的坐标点,转换为百度地图api 需要的坐标点
      trackPoint.push(new window.BMap.Point(point.lon, point.lat));
    }

    // 绘制服务区       fillColor 填充颜色
    let polygon = new window.BMap.Polygon(trackPoint, {
      strokeColor: '#CE0000',
      strokeWeight: 4,
      strokeOpacity: 1,
      fillColor:'#ff8605',
      fillOpacity:0.4
    });

    this.map.addOverlay(polygon);
  };

6. 实例代码

// src/pages/order/detail.js
import React from 'react';
import {Card} from 'antd';
import axios from './../../axios/index';
import './detail.less';

export default class OrderDetail extends React.Component {

  state = {};

  componentDidMount() {
    // 通过this.props.match.params.     取路由中的id(router-v4)
    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.result,
        });
        this.renderMap(res.result);
      }
    });
  };

  // 初始化地图
  renderMap = (result) => {
    this.map = new window.BMap.Map('orderDetailMap');//new BMap.Map('orderDetailMap',,{enableMapClick:false});地图无法点击
    // this.map.centerAndZoom('北京', 11);
    // 添加地图控件
    this.addMapControl();
    // 调用路线图绘制方法
    this.drawBikeRoute(result.position_list); // 初始化完成绘制路线图

    // 调用服务区绘制方法
    this.drawServiceArea(result.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}));
  };

  // 绘制用户的行驶路线
  // 需要坐标点(positionList)做参数
  drawBikeRoute = (positionList) => {
    let map = this.map; // 通过map 拿到地图的对象
    let startPoint = '';
    let endPoint = '';
    if (positionList.length > 0) {
      let first = positionList[0]; // 第一个坐标点
      let last = positionList[positionList.length - 1]; // 第一个坐标点
      startPoint = new window.BMap.Point(first.lon, first.lat); // arr.lon 经度 arr.lat 纬度

      // 创建起始坐标点的图标(Icon),设置Icon图标的大小(宽:36,高:42)
      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)
      });


      // 创建标注
      // 定义Marker 将图标放入页面(坐标点,图标)
      let startMarker = new window.BMap.Marker(startPoint, {icon: startIcon});

      // 将标注添加到地图中
      this.map.addOverlay(startMarker);


      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++) {
        // 换了个名称,用point 代替positionList 显得简洁
        let point = positionList[i];
        // 将接口返回的坐标点,转换为百度地图api 需要的坐标点
        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++) {
      // 换了个名称,用point 代替positionList 显得简洁
      let point = positionList[i];
      // 将接口返回的坐标点,转换为百度地图api 需要的坐标点
      trackPoint.push(new window.BMap.Point(point.lon, point.lat));
    }

    // 绘制服务区       fillColor 填充颜色
    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 || {};//如果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}公里</div>
              </li>
            </ul>
          </div>
        </Card>
      </div>
    );
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小李科技

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值