王贵旺 4 år sedan
förälder
incheckning
dbb85ef149

+ 5 - 0
.eslintrc.js

@@ -1,5 +1,10 @@
 module.exports = {
   root: true,
+  globals: {
+    BMapGL: true,
+    BMapGLLib: true,
+    BMAP_STATUS_SUCCESS: true
+  },
   env: {
     node: true
   },

BIN
src/assets/images/home/begin@2x.png


BIN
src/assets/images/home/end@2x.png


BIN
src/assets/images/home/phone@2x.png


BIN
src/assets/images/home/play.png


BIN
src/assets/images/home/red@2x.png


BIN
src/assets/images/home/stop.png


BIN
src/assets/images/home/stopwatch@2x.png


BIN
src/assets/images/home/trail-back@2x.png


+ 124 - 26
src/assets/index.scss

@@ -7,6 +7,17 @@
 .color-blue {
   color: #2979ff;
 }
+.slider-custom-button {
+  width: 15px;
+  height: 15px;
+  background-repeat: no-repeat;
+  background-position: center;
+  background-size: contain;
+  background-image: url(images/home/trail-back@2x.png);
+}
+.van-slider--disabled {
+  opacity: 1 !important;
+}
 .battle-warp {
   height: 100%;
   .van-checkbox {
@@ -405,6 +416,103 @@
       background-image: url(images/home/map-draw@2x.png);
     }
   }
+  .item-info .item-info__user, .item-header {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+  }
+  .footer-wrap {
+    height: 45px;
+    width: 260px;
+    position: absolute;
+    bottom: 30px;
+    border-radius: 25px;
+    background-color: #ffffff;
+    left: 50%;
+    margin-left: -130px;
+    z-index: 10000;
+    box-shadow: 0px 0px 5px 1px rgba(28, 29, 33, 0.16);
+
+    display: flex;
+    align-items: center;
+    justify-content: space-around;
+    .phone, .stopwatch {
+      width: 50%;
+      height: 25px;
+      line-height: 25px;
+      padding-left: 30px;
+      background-size: 21px 21px;
+      background-repeat: no-repeat;
+      color: #2979FF;
+    }
+    .phone {
+      border-right: 1px solid #dfdfdf;
+      background-position: 18px center;
+      background-image: url(images/home/phone@2x.png);
+    }
+    .stopwatch {
+      background-position: 25px center;
+      background-image: url(images/home/stopwatch@2x.png);
+    }
+  }
+  .footer-trail-wrap {
+    width: 350px;
+    position: absolute;
+    bottom: 12px;
+    left: 50%;
+    margin-left: -175px;
+    z-index: 10000;
+    text-align: left;
+
+    .back-time-list {
+      padding: 10px 0;
+      .van-tag {
+        margin-right: 10px;
+      }
+    }
+    .back-info-wrap {
+      padding: 12px;
+      border-radius: 4px;
+      background-color: #ffffff;
+      box-shadow: 0px 0px 5px 1px rgba(28, 29, 33, 0.16);
+      .data-info {
+        display: flex;
+        font-size: 12px;
+        padding: 8px 15px;
+        border-radius: 2px;
+        background-color: #ededed;
+        justify-content: space-between;
+      }
+      .back-time {
+        display: flex;
+        padding: 10px 0;
+        align-items: center;
+        justify-content: space-between;
+      }
+    }
+  }
+  .item-header {
+    height: 36px;
+    margin-bottom: 5px;
+    border-bottom: 1px solid #efeff4;
+  }
+  .driver-wrap {
+    display: flex;
+    width: 100%;
+    overflow: hidden;
+    overflow-x: auto;
+    .driver-list {
+      padding: 4px 8px;
+      background-color: #2979FF;
+      border-radius: 2px;
+      margin-right: 8px;
+      color: #ffffff;
+      white-space: nowrap;
+      &:last-child {
+        margin-right: 0;
+      }
+    }
+  }
   .list-wrap {
     color: #1c1d21;
     padding: 10px 15px;
@@ -420,8 +528,9 @@
       color: #868B9A;
       display: flex;
       justify-content: center;
-      align-items: end;
+      align-items: flex-end;
     }
+
     &__item {
       padding: 12px;
       text-align: left;
@@ -430,16 +539,22 @@
       background-color: #ffffff;
       box-shadow: 0px 0px 10px 1px rgba(28, 29, 33, 0.02);
 
-      .item-info .item-info__user, .item-header {
+      &.truck {
+        padding: 0;
+        margin-bottom: 0;
         display: flex;
         align-items: center;
-        justify-content: space-between;
-      }
-
-      .item-header {
-        height: 36px;
-        margin-bottom: 5px;
-        border-bottom: 1px solid #efeff4;
+        justify-content: flex-start;
+        .volume {
+          flex: 1;
+          height: 50px;
+          line-height: 50px;
+          padding-left: 40px;
+          background-size: 32px 32px;
+          background-repeat: no-repeat;
+          background-position: left center;
+          background-image: url(images/home/red@2x.png);
+        }
       }
       .item-info .label {
         padding: 5px 0;
@@ -460,23 +575,6 @@
         &:last-child {
           margin-bottom: 0;
         }
-        .driver-wrap {
-          display: flex;
-          width: 60%;
-          overflow: hidden;
-          overflow-x: auto;
-          .driver-list {
-            padding: 4px 8px;
-            background-color: #2979FF;
-            border-radius: 2px;
-            margin-right: 8px;
-            color: #ffffff;
-            white-space: nowrap;
-            &:last-child {
-              margin-right: 0;
-            }
-          }
-        }
         .status {
           font-size: 10px;
           border-radius: 2px;

+ 10 - 0
src/router/index.js

@@ -14,6 +14,16 @@ const routes = [
     name: 'list',
     meta: { title: '搜索车辆' },
     component: () => import('@/views/home/list')
+  }, {
+    path: '/truck',
+    name: 'truck',
+    meta: { title: '车辆信息' },
+    component: () => import('@/views/home/truck')
+  }, {
+    path: '/trail',
+    name: 'trail',
+    meta: { title: '轨迹回放' },
+    component: () => import('@/views/home/trail')
   }
 ]
 

+ 11 - 0
src/service/gasdata.js

@@ -1,5 +1,16 @@
 import R from '@/utils/request'
 
+// 物流公司所有车辆
 export async function $gasdataGaugeAll (data) {
   return await R({ url: 'gasdata/gauge/all', data })
 }
+
+// 单个车信息
+export async function $gasdataTruckInfo (data) {
+  return await R({ url: 'gasdata/gauge/one', data })
+}
+
+// 单个车回放轨迹
+export async function $gasdataTruckTrajectory (data) {
+  return await R({ url: 'gasdata/gauge/trajectory', data })
+}

+ 53 - 0
src/utils/map.js

@@ -0,0 +1,53 @@
+
+/**
+ * 异步加载百度地图
+ * @returns {Promise}
+ * @constructor
+ */
+export function loadBaiDuMap() {
+  return new Promise(function (resolve, reject) {
+    try {
+      console.log('BMap is defined:', BMapGL === undefined || BMapGL)
+      resolve(BMapGL)
+    } catch (err) {
+      window.init = function () {
+        resolve(BMapGL)
+      }
+      const script = document.createElement('script')
+      script.type = 'text/javascript'
+      script.src = `http://api.map.baidu.com/api?v=1.0&type=webgl&ak=${ak}&callback=init`
+      script.onerror = reject
+      document.body.appendChild(script)
+    }
+  })
+}
+
+/**
+ * 异步加载百度地图,以及绘制工具
+ * @returns {Promise}
+ * @constructor
+ */
+export function loadBaiDuDrawMap() {
+  return loadBaiDuMap().then(BMapGL => {
+    let loaded = false
+    try {
+      loaded = (BMapGLLib && BMapGLLib.DrawingManager)
+    } catch (err) {
+      loaded = false
+    }
+    if (!loaded) {
+      console.log('BMapLib.DrawingManager loading!')
+      const script = document.createElement('script')
+      script.type = 'text/javascript'
+      script.src = 'http://mapopen.cdn.bcebos.com/github/BMapGLLib/DrawingManager/src/DrawingManager.min.js'
+      document.body.appendChild(script)
+      const link = document.createElement('link')
+      link.rel = 'stylesheet'
+      link.href = 'http://mapopen.cdn.bcebos.com/github/BMapGLLib/DrawingManager/src/DrawingManager.min.css'
+      document.body.appendChild(link)
+    } else {
+      console.log('BMapLib.DrawingManager is loaded!')
+    }
+    return BMapGL
+  })
+}

+ 2 - 1
src/utils/vant.js

@@ -1,5 +1,5 @@
 import Vue from 'vue'
-import { Toast, Dialog, Button, Checkbox, Field, Icon, Popup, TreeSelect, List, Cell, CellGroup, Form, NumberKeyboard, Row, Col, PullRefresh, DatetimePicker, Loading, DropdownMenu, DropdownItem, Search, Tag, CountDown, RadioGroup, Radio, Switch, Calendar, Picker, Uploader, Tab, Tabs, Divider, ActionSheet, NoticeBar, Steps, Step, Swipe, SwipeItem, Tabbar, TabbarItem, Image as VanImage } from 'vant'
+import { Toast, Dialog, Button, Checkbox, Field, Icon, Popup, TreeSelect, List, Cell, CellGroup, Form, NumberKeyboard, Row, Col, PullRefresh, DatetimePicker, Loading, DropdownMenu, DropdownItem, Search, Tag, CountDown, RadioGroup, Radio, Switch, Calendar, Picker, Uploader, Tab, Tabs, Divider, ActionSheet, NoticeBar, Steps, Step, Swipe, SwipeItem, Tabbar, TabbarItem, Image as VanImage, Slider } from 'vant'
 
 Vue.use(Toast)
 Vue.use(Dialog)
@@ -42,3 +42,4 @@ Vue.use(SwipeItem)
 Vue.use(Tabbar)
 Vue.use(TabbarItem)
 Vue.use(VanImage)
+Vue.use(Slider)

+ 27 - 13
src/views/home/index.vue

@@ -13,18 +13,18 @@
             <van-dropdown-item v-model="tradeStatus" :options="tradeStatusList" @change="dropLoad" />
             <van-dropdown-item v-model="runStatus" :options="runStatusList" @change="dropLoad" />
           </van-dropdown-menu>
-          <div><van-icon name="search" /></div>
+          <div><van-icon name="search" @click="searchEvent" /></div>
         </div>
       </div>
     </div>
     <div class="list-icon" :class="showType === 1 ? 'list' : 'map'" @click="mapToListEvent">
       <div style="font-size: 14px;margin-top: 42px;">{{ showType === 1 ? '列表' : '地图' }}</div>
     </div>
-    <el-bmap v-if="nextTickStatus && showType === 1" vid="bmap" :zoom="zoom" :center="center" class="bm-view" :style="mapStyle">
+    <el-bmap v-if="showType === 1" vid="bmap" :zoom="zoom" :center="center" class="bm-view" :style="mapStyle">
       <el-bmap-marker v-for="(marker, index) in markers" :key="index" :icon="marker.icon" :visible="marker.visible" :position="marker.position" :title="marker.title" :label="marker.label" :events="marker.events" :vid="index" :enable-dragging="marker.enableDragging"></el-bmap-marker>
     </el-bmap>
-    <div v-else-if="nextTickStatus && showType === 2" class="list-wrap">
-      <div class="list-wrap__item" v-for="(item, index) in truckList" :key="index">
+    <div v-else-if="showType === 2" class="list-wrap">
+      <div class="list-wrap__item" v-for="(item, index) in truckList" :key="index" @click.native="clickTruckEvent(item)">
         <div class="item-header">
           <div class="text-bold">{{ item.carNumber }}<span class="text-normal">({{ item.linked === 1 ? '其他' : '自营' }})</span></div>
           <div>今日里程<span class="color-blue">{{ item.mileage || '-' }}</span>公里</div>
@@ -32,9 +32,9 @@
         <div class="item-info">
           <div class="label item-info__user" style="padding-left: 0" v-if="item.truckDriverList.length > 0">
             <div class="driver-wrap">
-              <div v-for="(driver, driverIndex) in item.truckDriverList" :key="driverIndex" class="driver-list">{{ truckToDriverUser(driver) }}</div>
+              <div v-for="(driver, driverIndex) in item.truckDriverList" :key="driverIndex" class="driver-list">{{ driver.driverName }}</div>
             </div>
-            <div>{{ truckToDriverMobile(item.truckDriverList[0].driverName) }}</div>
+<!--            <div>{{ truckToDriverMobile(item.truckDriverList[0].driverName) }}</div>-->
           </div>
           <div class="label speed">
             <span>{{ item.speed || '-' }}</span>公里/小时
@@ -49,11 +49,7 @@
 <script>
 import 'vue-bmap-gl/dist/style.css'
 import axios from 'axios'
-// import { $districtList, $userFindConfigAreaList } from '@/service/user'
 import { $gasdataGaugeAll } from '@/service/gasdata'
-// import { currency, formateZeroToBar } from '@/utils/filters'
-// import { MarkerWindow, AreaDataAnalysis } from './components'
-// import { mapJsonData } from '@/mock/map'
 export default {
   name: 'battle',
   // components: { MarkerWindow, AreaDataAnalysis },
@@ -107,8 +103,7 @@ export default {
         2: '离线中'
       },
       truckList: [],
-      markers: [],
-      nextTickStatus: true
+      markers: []
     }
   },
   watch: {},
@@ -175,6 +170,9 @@ export default {
       }
       return angleVal
     },
+    searchEvent() {
+      this.$router.push({ path: '/list' })
+    },
     mapToListEvent() {
       this.showType = this.showType === 1 ? 2 : 1
     },
@@ -192,6 +190,17 @@ export default {
         return '-'
       }
     },
+    clickTruckEvent(item) {
+      this.$router.push({
+        path: '/truck',
+        query: {
+          lat: item.lat,
+          lng: item.lng,
+          linked: item.linked,
+          carNumber: item.carNumber
+        }
+      })
+    },
     dropLoad() {
       this.dragendPointer()
     },
@@ -234,7 +243,12 @@ export default {
         icon: {},
         label: {},
         visible: true,
-        enableDragging: false
+        enableDragging: false,
+        events: {
+          click: () => {
+            this.clickTruckEvent(item)
+          }
+        }
       }
 
       info.label = {

+ 3 - 2
src/views/home/list.vue

@@ -11,9 +11,9 @@
         <div class="item-info">
           <div class="label item-info__user" style="padding-left: 0" v-if="item.truckDriverList.length > 0">
             <div class="driver-wrap">
-              <div v-for="(driver, driverIndex) in item.truckDriverList" :key="driverIndex" class="driver-list">{{ truckToDriverUser(driver) }}</div>
+              <div v-for="(driver, driverIndex) in item.truckDriverList" :key="driverIndex" class="driver-list">{{ driver.driverName }}</div>
             </div>
-            <div>{{ truckToDriverMobile(item.truckDriverList[0].driverName) }}</div>
+<!--            <div>{{ truckToDriverMobile(item.truckDriverList[0].driverName) }}</div>-->
           </div>
           <div class="label speed">
             <span>{{ item.speed || '-' }}</span>公里/小时
@@ -46,6 +46,7 @@ export default {
   watch: {},
   computed: {},
   created() {
+    document.title = 'skkss'
     this.dragendPointer()
   },
   mounted() {},

+ 356 - 0
src/views/home/trail.vue

@@ -0,0 +1,356 @@
+<template>
+  <div class="battle-warp">
+    <div class="map-card-wrap map">
+      <div class="map-card-wrap__info map">
+        <div class="item-header" style="padding: 3px 15px;border-color: #dddddd;">
+          <div class="text-bold">{{ queryTruckInfo.carNumber }}<span class="text-normal">({{ queryTruckInfo.linked === 1 ? '其他' : '自营' }})</span></div>
+          <div><span class="color-blue">{{ truckInfo.uploadTime || '-' }}</span></div>
+        </div>
+        <div class="label item-info__user" style="padding-left: 0;margin: 10px 15px;padding-bottom: 10px;border-bottom: 1px solid #f3f4f5;display: flex;justify-content: space-between;align-items: center;" v-if="truckInfo.hasOwnProperty('truckDriverList') && truckInfo.truckDriverList.length > 0">
+          <div class="driver-wrap" style="width: 85%;">
+            <div v-for="(driver, driverIndex) in truckInfo.truckDriverList" :key="driverIndex" class="driver-list">{{ driver.driverName }}</div>
+          </div>
+          <div><van-icon :name="showStatus ? 'arrow-down' : 'arrow-up'" @click="showStatus = !showStatus" /></div>
+        </div>
+        <van-row v-if="showStatus" class="map-card-wrap__info-box" :gutter="3" type="flex" justify="space-around">
+          <van-col :span="6" class="item" v-for="(item, index) of cardList" :key="index">
+            <div class="name">{{ item.name }}</div>
+            <div class="value">{{ item.value }} <span class="unit">{{ item.unit }}</span></div>
+          </van-col>
+        </van-row>
+        <template v-else>
+          <div class="list-wrap__item truck">
+            <div class="map-card-wrap__info-box">
+              <div class="item">
+                <div class="name">今日里程</div>
+                <div class="value">{{ truckInfo.mileage.toFixed(0) }} <span class="unit">公里</span></div>
+              </div>
+            </div>
+            <div class="item-info">
+              <div class="label speed">
+                <span>{{ truckInfo.speed || '-' }}</span>公里/小时
+                <span class="status" :class="'status__' + truckInfo.speedStatus">{{ truckStatusList[truckInfo.speedStatus] }}</span>
+              </div>
+              <div class="label local">{{ truckInfo.currAddress || '-' }}</div>
+            </div>
+          </div>
+          <div class="list-wrap__item truck">
+            <div class="map-card-wrap__info-box">
+              <div class="item">
+                <div class="name">今日耗能</div>
+                <div class="value">{{ truckInfo.consumption }} <span class="unit">公斤</span></div>
+              </div>
+            </div>
+            <div class="volume">剩余气量:{{ truckInfo.filterPercent > 0 ? `${truckInfo.filterPercent}%` : '无' }}</div>
+            <div class="map-card-wrap__info-box">
+              <div class="item">
+                <div class="name">今日减碳</div>
+                <div class="value">{{ truckInfo.carbon }} <span class="unit">公斤</span></div>
+              </div>
+            </div>
+
+          </div>
+        </template>
+      </div>
+    </div>
+    <div class="footer-trail-wrap">
+      <div>回放时段</div>
+      <div class="back-time-list">
+        <van-tag :color="timeStatus === 9 ? '#2979ff' : '#ffffff'" :text-color="timeStatus === 9 ? '#ffffff' : '#868b9a'" size="large" @click="timeEvent(9)">自定义</van-tag>
+        <van-tag :color="timeStatus === 1 ? '#2979ff' : '#ffffff'" :text-color="timeStatus === 1 ? '#ffffff' : '#868b9a'" size="large" @click="timeEvent(1)">近1天</van-tag>
+        <van-tag :color="timeStatus === 2 ? '#2979ff' : '#ffffff'" :text-color="timeStatus === 2 ? '#ffffff' : '#868b9a'" size="large" @click="timeEvent(2)">近3天</van-tag>
+        <van-tag :color="timeStatus === 3 ? '#2979ff' : '#ffffff'" :text-color="timeStatus === 3 ? '#ffffff' : '#868b9a'" size="large" @click="timeEvent(3)">近7天</van-tag>
+      </div>
+      <div class="back-info-wrap">
+        <div class="data-info">
+          <div>总里程 {{ truckTrialInfo.mileage }}公里</div>
+          <div>总能耗 {{ truckTrialInfo.consumption }}公斤</div>
+          <div>总减碳 {{ truckTrialInfo.carbon }}公斤</div>
+        </div>
+        <div style="width: 100%;padding: 30px 0 10px;">
+          <van-slider v-model="backValue" bar-height="4px" disabled>
+            <template #button>
+              <div class="slider-custom-button"> </div>
+            </template>
+          </van-slider>
+        </div>
+        <div class="back-time">
+          <div>{{ datatime.startTime }}</div>
+          <div @click="playTrailEvent()"><van-image width="28px" height="28px" fit="contain" :src="requestImages()"/></div>
+          <div>{{ datatime.endTime }}</div>
+        </div>
+      </div>
+    </div>
+    <el-bmap vid="bmap" :min-zoom="8" :max-zoom="20" :zoom="zoom" :center="center" :bmap-manager="bmapManager" class="bm-view" :style="mapStyle" :events="events"></el-bmap>
+  </div>
+</template>
+<script>
+import 'vue-bmap-gl/dist/style.css'
+import axios from 'axios'
+import { BMapManager } from 'vue-bmap-gl'
+import { $gasdataTruckInfo, $gasdataTruckTrajectory } from '@/service/gasdata'
+import { formatDate } from '@/utils/tools'
+// import { transformFromWGSToGCJ, transformFromGCJToBaidu } from '@/utils/wscoordinate'
+export default {
+  name: 'battle',
+  data() {
+    return {
+      backValue: 0,
+      timeStatus: 1,
+      showStatus: true,
+      playStatus: 1,
+      datatime: {
+        startTime: formatDate((new Date().getTime() - 86400000), 'yyyy-MM-dd hh:mm:ss'),
+        endTime: formatDate(new Date().getTime(), 'yyyy-MM-dd hh:mm:ss')
+      },
+      truckInfo: {},
+      truckTrialInfo: {},
+      queryTruckInfo: this.$route.query,
+      bmapManager: new BMapManager(),
+      map: null,
+      mapStyle: {
+        width: '100%',
+        height: '100%'
+      },
+      center: [this.$route.query.lng, this.$route.query.lat],
+      zoom: 10,
+      events: {
+        init: (map) => {
+          this.map = map
+          this.initTrailData()
+          // this.startDemo(o)
+        }
+      },
+      timer: null,
+      mapHeight: 400,
+      cardList: [{
+        name: '今日里程',
+        value: '0',
+        unit: '公里'
+      }, {
+        name: '今日耗能',
+        value: '0',
+        unit: '公斤'
+      }, {
+        name: '今日减碳',
+        value: '0',
+        unit: '公斤'
+      }],
+      truckStatusList: {
+        0: '行驶中',
+        1: '静止中',
+        2: '离线中'
+      },
+      lushu: null
+    }
+  },
+  watch: {},
+  computed: {},
+  created() {
+    this.dragendPointer()
+    // this.truckTrailInfo()
+  },
+  mounted() {
+    // 重置地图高度
+    this.mapHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
+  },
+  beforeDestroy() {},
+  methods: {
+    initData() {
+      let loaded = false
+      try {
+        loaded = (BMapGLLib && BMapGLLib.Lushu)
+      } catch (err) {
+        loaded = false
+      }
+
+      if (!loaded) {
+        console.log('BMapGLLib.Lushu loading!')
+        const lushu = document.createElement('script')
+        lushu.type = 'text/javascript'
+        lushu.src = 'https://mapopen.bj.bcebos.com/github/BMapGLLib/Lushu/src/Lushu.min.js'
+        document.body.appendChild(lushu)
+        const trackAnimation = document.createElement('script')
+        trackAnimation.type = 'text/javascript'
+        trackAnimation.src = 'https://mapopen.bj.bcebos.com/github/BMapGLLib/TrackAnimation/src/TrackAnimation.min.js'
+        document.body.appendChild(trackAnimation)
+      } else {
+        console.log('BMapGLLib.Lushu is loaded!')
+      }
+    },
+    timeEvent(type) {
+      this.timeStatus = Number(type)
+
+      if (this.timeStatus === 1) {
+        this.datatime = {
+          startTime: formatDate((new Date().getTime() - 86400000), 'yyyy-MM-dd hh:mm:ss'),
+          endTime: formatDate(new Date().getTime(), 'yyyy-MM-dd hh:mm:ss')
+        }
+      } if (this.timeStatus === 2) {
+        this.datatime = {
+          startTime: formatDate((new Date().getTime() - 3 * 86400000), 'yyyy-MM-dd hh:mm:ss'),
+          endTime: formatDate(new Date().getTime(), 'yyyy-MM-dd hh:mm:ss')
+        }
+      } if (this.timeStatus === 3) {
+        this.datatime = {
+          startTime: formatDate((new Date().getTime() - 7 * 86400000), 'yyyy-MM-dd hh:mm:ss'),
+          endTime: formatDate(new Date().getTime(), 'yyyy-MM-dd hh:mm:ss')
+        }
+      }
+
+      this.initTrailData()
+    },
+    requestImages () {
+      if (this.playStatus === 1) {
+        return require('@/assets/images/home/play.png')
+      } else {
+        return require('@/assets/images/home/stop.png')
+      }
+    },
+    playTrailEvent() {
+      if (this.playStatus === 1) {
+        this.playStatus = 2
+        this.lushu.start()
+      } else {
+        this.playStatus = 1
+        this.lushu.pause()
+      }
+    },
+    async initTrailData() {
+      this.initData()
+      const truckInfo = await this.truckTrailInfo()
+      const arrPois = truckInfo.points || []
+
+      const len = arrPois.length - 1
+      // const beginPoint = transformFromWGSToGCJ(arrPois[0].lat, arrPois[0].lng)
+      // const endPoint = transformFromWGSToGCJ(arrPois[len].lat, arrPois[len].lng)
+      // const baiduBeginPoint = transformFromGCJToBaidu(beginPoint.latitude, beginPoint.longitude)
+      // const baiduEndPoint = transformFromGCJToBaidu(endPoint.latitude, endPoint.longitude)
+      // console.log(baiduBeginPoint, baiduEndPoint)
+
+      var start = new BMapGL.Point(arrPois[0].lng, arrPois[0].lat)
+      var end = new BMapGL.Point(arrPois[len].lng, arrPois[len].lat)
+      var drv = new BMapGL.DrivingRoute(this.map, {
+        onSearchComplete: (res) => {
+          if (drv.getStatus() == BMAP_STATUS_SUCCESS) {
+            this.map.clearOverlays()
+            // 增加起点和终点坐标
+            this.map.addOverlay(new BMapGL.Marker(start, {
+              offset: new BMapGL.Size(0, -12),
+              icon: new BMapGL.Icon(require('@/assets/images/home/begin@2x.png'), new BMapGL.Size(20, 26))
+            }))
+            this.map.addOverlay(new BMapGL.Marker(end, {
+              offset: new BMapGL.Size(0, -12),
+              icon: new BMapGL.Icon(require('@/assets/images/home/end@2x.png'), new BMapGL.Size(20, 26))
+            }))
+
+            this.map.addOverlay(new BMapGL.Polyline(arrPois, { strokeColor: '#43bf91', strokeOpacity: 1 }))
+            this.map.setViewport(arrPois)
+
+            this.lushu = new BMapGLLib.LuShu(this.map, arrPois, {
+              defaultContent: '', // 覆盖物中的内容 "从天安门到百度大厦"
+              autoView: true, // 是否开启自动视野调整,如果开启那么路书在运动过程中会根据视野自动调整
+              icon: new BMapGL.Icon(require('@/assets/images/home/red@2x.png'), new BMapGL.Size(15, 15), { anchor: new BMapGL.Size(10, 10) }),
+              speed: 10, // 覆盖物移动速度,单位米/秒
+              enableRotation: true // 是否设置marker随着道路的走向进行旋转
+              // landmarkPois: [
+              //   { lng: 116.314782, lat: 39.913508, html: '加油站', pauseTime: 2 },
+              //   { lng: 116.315391, lat: 39.964429, html: '高速公路收费<div><img src="//map.baidu.com/img/logo-map.gif"/></div>', pauseTime: 3 },
+              //   { lng: 116.381476, lat: 39.974073, html: '肯德基早餐', pauseTime: 2 }
+              // ]
+            })
+          }
+        }
+      })
+
+      drv.search(start, end)
+    },
+    async queryCurrAddress(location) {
+      const data = await axios.post(process.env.VUE_APP_BAIDU_URL + '?output=json&ak=Zvd6FzmertUwjhZih5Zfq0D8uTUhvqsH&coordtype=wgs84ll&location=' + location).then(response => {
+        return response.data
+      })
+
+      if (data.hasOwnProperty('result')) {
+        return data.result.addressComponent
+      } else {
+        return '-'
+      }
+    },
+    angle(start, end) {
+      // 通过 a、b 确定角度所处的象限
+      const a = start[0] - end[0]
+      const b = start[1] - end[1]
+      // eslint-disable-next-line camelcase
+      const a_c = Math.abs(a)
+      // eslint-disable-next-line camelcase
+      const b_c = Math.abs(b)
+      // 获取得三角形的斜边 Math.hypot();
+      const c = Math.hypot(a_c, b_c)
+      // 计算弧度
+      // eslint-disable-next-line camelcase
+      const radina = Math.acos(a_c / c)
+      // 计算角度
+      let angleVal = Math.floor(radina * 180 / Math.PI)
+      // 处理最终需要旋转的角度
+      if (a > 0) {
+        // 第二、三象限
+        if (b > 0) {
+          // 三
+          angleVal = 90 + 90 - angleVal
+        } else {
+          angleVal = -180 + angleVal
+        }
+      } else {
+        // 一、四象限
+        if (b > 0) {
+          // 四
+          // eslint-disable-next-line no-self-assign
+          angleVal = angleVal
+        } else {
+          // 一
+          angleVal = -angleVal
+        }
+      }
+      return angleVal
+    },
+    async truckTrailInfo() {
+      const params = {
+        carNumber: this.queryTruckInfo.carNumber,
+        days: (this.timeStatus === 9 ? 0 : this.timeStatus),
+        startTime: this.datatime.startTime,
+        endTime: this.datatime.endTime
+      }
+      const data = await $gasdataTruckTrajectory(params).then(response => {
+        return response
+      })
+      this.truckTrialInfo = data
+
+      return data
+    },
+    dragendPointer() {
+      const params = {
+        carNumber: this.queryTruckInfo.carNumber
+      }
+
+      this.markers = []
+      $gasdataTruckInfo(params).then(async response => {
+        this.truckInfo = response
+        // 统计数据
+        this.cardList[0].value = response.mileage.toFixed(0)
+        this.cardList[1].value = response.consumption
+        this.cardList[2].value = response.carbon
+
+        // 根据金纬度获取地理位置信息
+        const addressInfo = await this.queryCurrAddress(response.lat + ',' + response.lng)
+        const currAddress = addressInfo.province + addressInfo.city + addressInfo.district + addressInfo.street
+
+        if (response.hasOwnProperty('currAddress')) {
+          response.currAddress = currAddress
+        } else {
+          this.$set(response, 'currAddress', currAddress)
+        }
+      })
+    }
+  }
+}
+</script>

+ 229 - 0
src/views/home/truck.vue

@@ -0,0 +1,229 @@
+<template>
+  <div class="battle-warp">
+    <div class="map-card-wrap map">
+      <div class="map-card-wrap__info map">
+        <div class="item-header" style="padding: 3px 15px;border-color: #dddddd;">
+          <div class="text-bold">{{ queryTruckInfo.carNumber }}<span class="text-normal">({{ queryTruckInfo.linked === 1 ? '其他' : '自营' }})</span></div>
+          <div><span class="color-blue">{{ truckInfo.uploadTime || '-' }}</span></div>
+        </div>
+        <div class="label item-info__user" style="padding-left: 0;margin: 10px 15px;padding-bottom: 10px;border-bottom: 1px solid #f3f4f5;display: flex;justify-content: space-between;align-items: center;" v-if="truckInfo.hasOwnProperty('truckDriverList') && truckInfo.truckDriverList.length > 0">
+          <div class="driver-wrap" style="width: 85%;">
+            <div v-for="(driver, driverIndex) in truckInfo.truckDriverList" :key="driverIndex" class="driver-list">{{ driver.driverName }}</div>
+          </div>
+          <div><van-icon :name="showStatus ? 'arrow-down' : 'arrow-up'" @click="showStatus = !showStatus" /></div>
+        </div>
+        <van-row v-if="showStatus" class="map-card-wrap__info-box" :gutter="3" type="flex" justify="space-around">
+          <van-col :span="6" class="item" v-for="(item, index) of cardList" :key="index">
+            <div class="name">{{ item.name }}</div>
+            <div class="value">{{ item.value }} <span class="unit">{{ item.unit }}</span></div>
+          </van-col>
+        </van-row>
+        <template v-else>
+          <div class="list-wrap__item truck">
+            <div class="map-card-wrap__info-box">
+              <div class="item">
+                <div class="name">今日里程</div>
+                <div class="value">{{ truckInfo.mileage.toFixed(0) }} <span class="unit">公里</span></div>
+              </div>
+            </div>
+            <div class="item-info">
+              <div class="label speed">
+                <span>{{ truckInfo.speed || '-' }}</span>公里/小时
+                <span class="status" :class="'status__' + truckInfo.speedStatus">{{ truckStatusList[truckInfo.speedStatus] }}</span>
+              </div>
+              <div class="label local">{{ truckInfo.currAddress || '-' }}</div>
+            </div>
+          </div>
+          <div class="list-wrap__item truck">
+            <div class="map-card-wrap__info-box">
+              <div class="item">
+                <div class="name">今日耗能</div>
+                <div class="value">{{ truckInfo.consumption }} <span class="unit">公斤</span></div>
+              </div>
+            </div>
+            <div class="volume">剩余气量:{{ truckInfo.filterPercent > 0 ? `${truckInfo.filterPercent}%` : '无' }}</div>
+            <div class="map-card-wrap__info-box">
+              <div class="item">
+                <div class="name">今日减碳</div>
+                <div class="value">{{ truckInfo.carbon }} <span class="unit">公斤</span></div>
+              </div>
+            </div>
+
+          </div>
+        </template>
+      </div>
+    </div>
+    <div class="footer-wrap">
+      <div class="phone">联系驾驶员</div>
+      <div class="stopwatch" @click="trailBackEvent">轨迹回放</div>
+    </div>
+    <el-bmap vid="bmap" :zoom="zoom" :center="center" class="bm-view" :style="mapStyle">
+      <el-bmap-marker v-for="(marker, index) in markers" :key="index" :icon="marker.icon" :visible="marker.visible" :position="marker.position" :title="marker.title" :label="marker.label" :events="marker.events" :vid="index" :enable-dragging="marker.enableDragging"></el-bmap-marker>
+    </el-bmap>
+  </div>
+</template>
+<script>
+import 'vue-bmap-gl/dist/style.css'
+import axios from 'axios'
+import { $gasdataTruckInfo } from '@/service/gasdata'
+export default {
+  name: 'battle',
+  data() {
+    return {
+      showStatus: true,
+      truckInfo: {},
+      queryTruckInfo: this.$route.query,
+      map: null,
+      mapStyle: {
+        width: '100%',
+        height: '100%'
+      },
+      center: [this.$route.query.lng, this.$route.query.lat],
+      zoom: 16,
+      timer: null,
+      mapHeight: 400,
+      cardList: [{
+        name: '今日里程',
+        value: '0',
+        unit: '公里'
+      }, {
+        name: '今日耗能',
+        value: '0',
+        unit: '公斤'
+      }, {
+        name: '今日减碳',
+        value: '0',
+        unit: '公斤'
+      }],
+      truckStatusList: {
+        0: '行驶中',
+        1: '静止中',
+        2: '离线中'
+      },
+      markers: []
+    }
+  },
+  watch: {},
+  computed: {},
+  created() {
+    this.dragendPointer()
+    this.timer = setInterval(() => {
+      this.dragendPointer()
+    }, 60000)
+  },
+  mounted() {
+    // 重置地图高度
+    this.mapHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
+  },
+  beforeDestroy() {
+    clearInterval(this.timer)
+  },
+  methods: {
+    trailBackEvent() {
+      this.$router.push({
+        path: '/trail',
+        query: this.queryTruckInfo
+      })
+    },
+    async queryCurrAddress(location) {
+      const data = await axios.post(process.env.VUE_APP_BAIDU_URL + '?output=json&ak=Zvd6FzmertUwjhZih5Zfq0D8uTUhvqsH&coordtype=wgs84ll&location=' + location).then(response => {
+        return response.data
+      })
+
+      if (data.hasOwnProperty('result')) {
+        return data.result.addressComponent
+      } else {
+        return '-'
+      }
+    },
+    angle(start, end) {
+      // 通过 a、b 确定角度所处的象限
+      const a = start[0] - end[0]
+      const b = start[1] - end[1]
+      // eslint-disable-next-line camelcase
+      const a_c = Math.abs(a)
+      // eslint-disable-next-line camelcase
+      const b_c = Math.abs(b)
+      // 获取得三角形的斜边 Math.hypot();
+      const c = Math.hypot(a_c, b_c)
+      // 计算弧度
+      // eslint-disable-next-line camelcase
+      const radina = Math.acos(a_c / c)
+      // 计算角度
+      let angleVal = Math.floor(radina * 180 / Math.PI)
+      // 处理最终需要旋转的角度
+      if (a > 0) {
+        // 第二、三象限
+        if (b > 0) {
+          // 三
+          angleVal = 90 + 90 - angleVal
+        } else {
+          angleVal = -180 + angleVal
+        }
+      } else {
+        // 一、四象限
+        if (b > 0) {
+          // 四
+          // eslint-disable-next-line no-self-assign
+          angleVal = angleVal
+        } else {
+          // 一
+          angleVal = -angleVal
+        }
+      }
+      return angleVal
+    },
+    dragendPointer() {
+      const params = {
+        carNumber: this.queryTruckInfo.carNumber
+      }
+
+      this.markers = []
+      $gasdataTruckInfo(params).then(async response => {
+        this.truckInfo = response
+        // 统计数据
+        this.cardList[0].value = response.mileage.toFixed(0)
+        this.cardList[1].value = response.consumption
+        this.cardList[2].value = response.carbon
+
+        this.markerInfo(response)
+        // 根据金纬度获取地理位置信息
+        const addressInfo = await this.queryCurrAddress(response.lat + ',' + response.lng)
+        const currAddress = addressInfo.province + addressInfo.city + addressInfo.district + addressInfo.street
+
+        if (response.hasOwnProperty('currAddress')) {
+          response.currAddress = currAddress
+        } else {
+          this.$set(response, 'currAddress', currAddress)
+        }
+      })
+    },
+    markerInfo(item) {
+      const info = {
+        icon: {},
+        label: {},
+        visible: true,
+        enableDragging: false
+      }
+
+      info.label = {
+        content: item.carNumber,
+        offset: [-23, -25],
+        style: {
+          borderWidth: 0,
+          padding: '3px 10px',
+          borderRadius: '4px',
+          boxShadow: '0px 0px 9px 1px rgba(28, 29, 33, 0.16)'
+        }
+      }
+      info.icon = {
+        url: require('@/assets/images/navigation/navigation@2x.png'),
+        size: [20, 26]
+      }
+      info.position = [item.lng, item.lat]
+
+      this.markers.push(info)
+    }
+  }
+}
+</script>