|
- <template>
- <div class="trajectory">
- <div class="trajectory-con">
- <div class="top">
- <van-nav-bar title="历史轨迹" left-arrow @click-left="onNavBack" left-text="返回" />
- <!-- 右边固定的时间选项 -->
- <div class="time-picker" :style="{ width: `${timePickWidth}%` }">
- <div class="time-picker-left" :style="{ width: `${timeWidth}%` }" @click="onTimeClick">
- <van-icon name="arrow-left" v-if="isLeft" />
- <van-icon name="arrow" v-if="!isLeft" />
- <span>时间</span>
- </div>
- <div class="time-picker-right" v-if="isPopup">
- <span @click="onStartClick" v-show="true">{{ initTimePick.initStartTime }}</span>
- <label class="labelTime">至</label>
- <span @click="onEndClick" v-show="true">{{ initTimePick.initEndTime }}</span>
- <van-datetime-picker
- v-model="timePickData.selectStartTime"
- v-show="timePickData.timePickStartShow"
- class="datetimePicker"
- type="time"
- title="选择开始时间"
- :min-hour="timePickData.defaultStartTime.slice(0, 2)"
- :max-hour="timePickData.defaultEndTime.slice(0, 2)"
- confirm-button-text="确定"
- @confirm="onStartTimeConfirm"
- @cancel="onStartTimeCancel"
- :item-height="itemHeight"
- />
- <van-datetime-picker
- v-model="timePickData.selecttEndTime"
- v-show="timePickData.timePickEndShow"
- class="datetimePicker"
- type="time"
- title="选择结束时间"
- :min-hour="timePickData.defaultStartTime.slice(0, 2)"
- :max-hour="timePickData.defaultEndTime.slice(0, 2)"
- @confirm="onEndTimeConfirm"
- confirm-button-text="确定"
- @cancel="onEndTimeCancel"
- :item-height="itemHeight"
- />
- </div>
- <div class="time-picker-right-confirm" @click="onConfirm" v-if="isPopup">
- <div class="right-confirm-text">
- <span>查看</span>
- </div>
- </div>
- </div>
- <div class="dateArea">
- <i class="left active" @click="dateClick"></i>
- <span @click="dateAreaClick">{{ new Date(date).Format('yyyy年MM月dd日') }}</span>
- <i :class="['right', { active: count < 0 }]" @click="dateClick('add')"></i>
- </div>
- <div class="calendar" v-show="calendarShow">
- <van-calendar
- v-model="calendarShow"
- :min-date="minDate"
- :max-date="maxDate"
- :default-date="defaultDate"
- :round="false"
- :poppable="false"
- :show-confirm="false"
- :show-title="false"
- :show-subtitle="false"
- @select="onSelect"
- />
- </div>
- </div>
- <!-- 轨迹地图部分 -->
- <div id="trajectory_map" class="index_map" style="width: 100%; height: 100vh"></div>
- <!-- 底部部分 -->
- <div class="bottom">
- <div class="conArea" v-show="bottomContentShow">
- <!-- 右边的速度滑块 -->
- <div class="slider-bar">
- <!--<span>速度</span>-->
- <span>慢</span>
- <div class="bar">
- <van-slider :min="min" :max="max" :step="step" v-model="leftCode" vertical />
- </div>
- <!--<div>{{leftCode}}</div>-->
- <!--<div>km/h</div>-->
- <span>快</span>
- </div>
- <!-- 下面的地址 时间 -->
- <div class="con">
- <span
- class="title"
- v-if="
- decoratedAddressList === null || (decoratedAddressList !== null && decoratedAddressList.length === 0)
- "
- >暂无地址信息</span
- >
- <div class="content-list" v-if="decoratedAddressList !== null && decoratedAddressList.length > 0">
- <div class="content-item" v-for="(item, index) in decoratedAddressList" :key="index">
- <p class="title">{{ item.address ? item.address + '(附近)' : '暂无位置信息' }}</p>
- <div class="states">
- <span v-if="item.s_time != item.repeat_last_time">
- {{ item.s_time.split(' ')[1] }}
- ~
- {{ item.repeat_last_time.split(' ')[1] }}
- </span>
- <span v-if="item.s_time == item.repeat_last_time">
- {{ item.time.split(' ')[1] }}
- </span>
- </div>
- </div>
- </div>
- </div>
- <!-- 播放按钮 -->
- <div class="player">
- <van-icon name="play-circle-o" v-show="!playFlag" @click="onPlay" />
- <van-icon name="pause-circle-o" v-show="playFlag" @click="onPause" />
- </div>
- </div>
- <!--<overlay-loading :showOverlay="showOverlay"></overlay-loading>-->
- </div>
- </div>
- </div>
- </template>
-
- <script>
- import MapLoader from '@/common/amap.js';
- import DialogService from '../../services/dialog-service';
- import ToastService from '../../services/toast-service';
- import { ErrorAMapMsgModel } from '../../config/models';
- import APIDevice from '../../api/device';
-
- export default {
- data() {
- const ms_TO_kmh = 3.6;
- return {
- ms_TO_kmh: ms_TO_kmh,
- showOverlay: true,
- lineArr: [],
- lineArrCopy: [],
- allLineArr: [],
- // map: null,
- marker: null,
- playFlag: false, //播放状态
- count: 0, //日期count
- date: this.$own.getNowFormatDate(0),
- clickFlag: true, //左右日期按钮是否给予点击
- bottomContentShow: true,
- address: '',
- time: '',
- calendarShow: false,
- minDate: /* new Date(2020, 0, 1) */ new Date(
- this.$dayjs()
- .month(this.$dayjs().month() - 1)
- .hour(0)
- .minute(0)
- .second(0)
- .format()
- ),
- maxDate: /* new Date() */ new Date(this.$dayjs().hour(0).minute(0).second(0).format()),
- defaultDate: /* new Date() */ new Date(this.$dayjs().hour(0).minute(0).second(0).format()),
- num: 0,
- playState: 'off',
- max: 8000,
- min: 100,
- leftCode: 100,
- step: 100,
- map: {
- instance: null,
- position: null,
- zoom: 15,
- marker: null,
- markerNew: null,
- polyline: null,
- polylineNew: null,
- passedPolyline: null,
- passedPolylineNew: null,
- graspRoad: null,
- walking: null,
- riding: null,
- transfer: null,
- city: null
- },
- speedTypes: {
- // 步行1m/S;骑车3m/S;汽车11m/S~16m/S;高铁16m/S~80m/S
- walking: 1.7 * ms_TO_kmh,
- riding: [1.7 * ms_TO_kmh, 6.6 * ms_TO_kmh],
- driving: [6.6 * ms_TO_kmh, 16.7 * ms_TO_kmh],
- // highRailway: [ 16.8 * ms_TO_kmh, 80 * ms_TO_kmh ],
- highRailway: [16.8 * ms_TO_kmh, 55.5 * ms_TO_kmh]
- },
- serviceTypes: {
- walking: 'walking',
- riding: 'riding',
- driving: 'driving',
- transfer: 'transfer',
- overTime: 'overTime',
- overSpeed: 'overSpeed',
- sameAddress: 'sameAddress'
- },
- dataList: [],
- path: [],
- polylineList: [],
- lngLatOnMoving: [],
- movingIndexOfPolylineList: 0,
- circleList: [],
- limitDistance: 50, // 聚集点距离
- limitSecond: 60 * 6, // 相邻点的时间差(作为直连线/上报缺点的依据)
- limitSpeed: 120, // km/h 超速(直连线)
- thresholdTime: 60 * 15, // 15 分钟;判断两个 driving 时间差是否符合该阀值
- decoratedAddressList: null,
- collectionStraightPoints: [], // 直连线的点的记录
- isPopup: false, //右上快捷时间选择器是否显示
- timePickWidth: 20, //时间选择器初始的百分比宽度
- timeWidth: 100, //时间选择器最大的百分比宽度
- isLeft: true, //时间选择器是否在左边.默认在左边
- itemHeight: Number(((document.body.clientWidth / 750) * 75).toFixed()), //时间选择器item的高度
- timePickData: {
- defaultStartTime: '00:00',
- defaultEndTime: '23:59',
- timePickStartShow: false,
- timePickEndShow: false,
- selectStartTime: '00:00',
- selecttEndTime: '23:59'
- }, //时间选择器
- initTimePick: {
- initStartTime: '00:00',
- initEndTime: '23:59'
- }, //初始化接口第一次获取的时间
- dialogShow: false, //轨迹对比弹窗是否显示
- dialogInput: '', //弹窗输入的json数据
- dataListNew: [],
- pathNew: [],
- polylineListNew: [],
- lngLatOnMovingNew: [],
- collectionStraightPointsNew: [],
- circleListNew: [],
- isProduction: process.env.NODE_ENV === 'production'
- };
- },
- mounted() {
- // this.getAmap();
-
- this.getMap();
- this.toggleBottom(true);
- },
- methods: {
- onNavBack() {
- this.$router.push({
- name: 'location'
- });
- },
- onPlay() {
- if (this.$own.isNull(this.polylineList)) {
- ToastService.fail({ message: '暂无信息' });
- return;
- }
- this.map.marker.moveAlong(this.polylineList, this.leftCode);
- console.log('dataList:::', this.dataList);
- },
- onPause() {
- this.map.marker.pauseMove();
- },
- // 去重、补上【开始时间、结束时间、重复项】
- deduplicatedANDDecorateList(dataList) {
- let result = [],
- repeatNum = 1;
- for (let i = 0; i < dataList.length; i++) {
- let preItem = dataList[i - 1 >= 0 ? i - 1 : 0];
- const currentItem = dataList[i];
- if (typeof currentItem === 'object' && Array.isArray(currentItem)) {
- // 兼容纯经纬度数组
- if (i === 0) {
- result.push(preItem);
- continue;
- }
- if (
- currentItem[0] === 0 ||
- currentItem[1] === 0 ||
- (currentItem[0] === preItem[0] && currentItem[1] === preItem[1])
- ) {
- result[result.length - 1] = currentItem;
- }
- } else {
- // 对象数组
- if (i === 0) {
- result.push({
- ...preItem,
- s_time: preItem.time.replace(new RegExp(/(-)/g), '/'),
- e_time: preItem.time.replace(new RegExp(/(-)/g), '/'),
- repeat_last_time: preItem.time.replace(new RegExp(/(-)/g), '/'),
- repeatNum: repeatNum
- });
- continue;
- }
- let last = result[result.length - 1];
- if (
- currentItem.lng === 0 ||
- currentItem.lat === 0 ||
- (currentItem.lng === preItem.lng && currentItem.lat === preItem.lat)
- ) {
- last = {
- ...last,
- // s_time: last.s_time,
- // e_time: last.time,
- repeat_last_time: currentItem.time.replace(new RegExp(/(-)/g), '/'), //正则 接口返回的时间数据(yyyy-MM-dd)ios系统不能识别,所以我们将它-变成/ (yyyy/MM/dd)
- repeatNum: ++repeatNum,
- distance: last.distance
- };
- result[result.length - 1] = last;
- } else {
- repeatNum = 1;
- const d = this.calculateDistanceByPoints([last.lng, last.lat], [currentItem.lng, currentItem.lat]);
- result.push({
- ...currentItem,
- s_time: currentItem.time.replace(new RegExp(/(-)/g), '/'),
- e_time: currentItem.time.replace(new RegExp(/(-)/g), '/'),
- repeat_last_time: currentItem.time.replace(new RegExp(/(-)/g), '/'),
- repeatNum: repeatNum,
- distance: d
- });
- }
- }
- }
- return result;
- },
- // 米
- calculateDistanceByPoints(s_lngLat, e_lngLat) {
- // eslint-disable-next-line
- return parseInt(AMap.GeometryUtil.distance(s_lngLat, e_lngLat));
- },
- // 筛选出聚集点
- decorateListCircle(dataList) {
- try {
- if (this.$own.isNull(dataList)) return [];
- if (dataList.length === 1) return [{ ...dataList[0], circle: false, clusterSize: 1 }];
- let result = [];
- let stack = [];
- for (let i = 0; i < dataList.length; i++) {
- const current = dataList[i];
- if (current.distance < this.limitDistance) {
- // 成为聚集点
- stack.push(current);
- } else {
- // 将之前的聚集点出栈
- let mid = stack[Math.floor(stack.length / 2)];
-
- result.push({
- ...mid,
- circle: stack.length > 1, //
- s_time: stack[0].s_time,
- e_time: stack[stack.length - 1].e_time,
- repeat_last_time: stack[stack.length - 1].repeat_last_time,
- distance: stack[stack.length - 1].distance,
- clusterSize: stack.length,
- skipService: false
- });
- // update栈
- stack = [{ ...current, circle: false }];
- }
- }
- if (stack.length > 0) {
- // 最后一项出栈
- if (stack.length > 1) {
- // 聚集点
- let mid = stack[Math.floor(stack.length / 2)];
- result.push({
- ...mid,
- circle: true,
- s_time: stack[0].s_time,
- e_time: stack[stack.length - 1].e_time,
- repeat_last_time: stack[stack.length - 1].repeat_last_time,
- distance: stack[stack.length - 1].distance,
- clusterSize: stack.length,
- skipService: false
- });
- } else {
- // length === 0
- result.push({ ...stack[0], circle: false, clusterSize: stack.length, skipService: false });
- }
- }
- return result;
- } catch (e) {
- console.log('decorateListCircle():::', e);
- }
- },
- decorateListAddress(dataList) {
- if (this.$own.isNull(dataList)) {
- return [];
- }
- if (dataList.length === 1) {
- return dataList;
- }
- let result = [];
- let temp = dataList[0] || null;
- for (let i = 1; i < dataList.length; i++) {
- const current = dataList[i];
- if (this.$own.isNotNull(temp) && temp.address === current.address) {
- temp = {
- ...current,
- s_time: temp.s_time
- };
- if (i === dataList.length - 1) {
- result.push(temp);
- }
- } else {
- result.push(temp);
- temp = current;
- if (i === dataList.length - 1) {
- result.push(current);
- }
- }
- }
- return result;
- },
- decorateListSpeed(dataList) {
- if (dataList.length === 1) return [{ ...dataList[0], sp: 0 }];
- let result = [],
- temp = null;
- result = dataList.map((item, i) => {
- if (i === 0) return { ...item, sp: 0 };
- temp = dataList[i - 1];
- const sp = (item.distance / this.calculateTime(temp.e_time, item.s_time)) * this.ms_TO_kmh; // km/h
- return {
- ...item,
- sp
- };
- });
- return result;
- },
- calculateTime(start, end) {
- // 计算两个时间之差(second)
- let s = new Date(start).getTime();
- let e = new Date(end).getTime();
- let dif = Math.abs(e - s) / 1000;
- return dif;
- },
- /**
- * 该函数目的在将路线数组标记上出行方式 walking riding driving transfer
- * 操作即从点到线段的层面
- */
- serviceTypeFilter(data) {
- const result = [];
- // 1、循环经纬度速度数组
- for (let i = 0; i < data.length; i++) {
- if (i === 0) {
- result.push(data[i]);
- continue;
- }
-
- const preItem = data[i - 1];
- const item = data[i];
- const timeDif = this.calculateTime(preItem.e_time, item.s_time);
- const address = preItem.address;
- if (timeDif >= this.limitSecond) {
- // 当相邻项的时间相隔超过规定时,直连线
- result.push({ ...item, serviceType: this.serviceTypes.overTime });
- continue;
- } else if (this.checkAddress(address, item.address)) {
- // 当相邻项的中文地址相同、包含时,直连线
- result.push({ ...item, serviceType: this.serviceTypes.sameAddress });
- continue;
- } else {
- // 根据速度分类出行方式 type
- result.push({ ...item, serviceType: this.getServiceType(item) });
- }
- } // for() {} done
- return result;
- },
- /**
- * 根据出行方式,而在规定时间区间内,若驾车方式中间夹着其他方式,则将其他方式修正为驾车(方便使用驾车的轨迹纠偏服务)
- * eg. p0-driving p1-walking p2-walking p3-walking p4-driving
- * p0 - p4 时间间隔不超过规定时间 如 15 分钟,则将 p1~p3 的方式改为 driving
- */
- changeToDriving(data) {
- let result = [];
- let nextDrivingIdx = -1;
- for (let i = 0; i < data.length; i++) {
- if (i === 0) {
- result.push(data[i]);
- continue;
- }
- if (data[i].serviceType !== this.serviceTypes.driving && nextDrivingIdx === -1) {
- result.push(data[i]);
- } else if (nextDrivingIdx - i > 0) {
- // 此时出现两个 driving 中间夹着其他方式,将一律改为 driving
- result.push({ ...data[i], serviceType: this.serviceTypes.driving });
- } else if (i < data.length - 2) {
- result.push(data[i]);
- nextDrivingIdx = this.findNextDriving(data, i + 1);
- if (!this.checkTimeDiff(data[i].time, data[nextDrivingIdx].time, this.thresholdTime)) {
- nextDrivingIdx = -1;
- }
- } else {
- result.push(data[i]);
- }
- }
- return result;
- },
- findNextDriving(data, start) {
- let end = 0;
- for (let i = start; i < data.length; i++) {
- if (data[i].serviceType !== this.serviceTypes.driving) {
- continue;
- } else {
- end = i;
- break;
- }
- }
- return end;
- },
- // 单位秒;判断两个时间之差是否在 threshold(阈值) 之内
- checkTimeDiff(start, end, threshold) {
- const startTm = new Date(start).getTime();
- const endTm = new Date(end).getTime();
- return (endTm - startTm) / 1000 <= threshold;
- },
- // 通过速度判断类型
- getServiceType(data) {
- if (data.address.indexOf('高速') >= 0)
- // 包含'高速'使用driving
- return 'driving';
- const sp = data.sp;
- return sp - this.limitSpeed >= 0
- ? 'overSpeed'
- : sp - this.speedTypes.highRailway[0] > 0
- ? 'transfer'
- : sp - this.speedTypes.driving[0] >= 0
- ? 'driving'
- : sp - this.speedTypes.riding[0] > 0
- ? 'riding'
- : 'walking';
- },
- calculateByContext(dataList) {
- let result = [];
- if (this.$own.isNull(dataList)) {
- return [];
- }
- if (dataList.length === 1) {
- return dataList;
- }
- let preWeight = 0;
- const maxWeight = 1;
- for (let i = 0; i < dataList.length; i++) {
- let weight = 0;
- let startP = dataList[i];
- let endP = i === dataList.length - 1 ? null : dataList[i + 1];
- if (endP === null) {
- result.push({ ...dataList[i], weight: preWeight || weight });
- continue;
- }
- const distance = this.calculateDistanceByPoints([startP.lng, startP.lat], [endP.lng, endP.lat]);
- const time = this.calculateTime(startP.e_time, endP.s_time);
- const speed = (distance / time) * this.ms_TO_kmh; // km/h
- if (speed <= this.speedTypes.highRailway[1]) {
- weight++;
- }
- result.push({ ...dataList[i], weight: weight || preWeight });
- preWeight = weight;
- }
- return result.filter(o => o.weight === maxWeight) || [];
- },
- // 通过步行服务获取经纬度
- getPathByWalkingService(data) {
- const routes = data.routes;
- let pathes = [];
- /*routes.forEach(route => {
- route.steps.forEach(step => {
- step.path.forEach(path => {
- pathes.push([ path.lng, path.lat ]);
- });
- });
- });*/
- // 默认拿第一个路线
- routes[0].steps.forEach(step => {
- step.path.forEach(path => {
- pathes.push([path.lng, path.lat]);
- });
- });
- return pathes;
- },
- // 通过公交服务获取经纬度
- getPathByTransferService(data) {
- let path = [];
- /*data.plans.forEach(plan => {
- path = path.concat(plan.path.map(item => {
- return [ item.lng, item.lat ];
- }));
- });*/
- // 默认拿第一个路线
- path = path.concat(
- data.plans[0].path.map(item => {
- return [item.lng, item.lat];
- })
- );
- return path;
- },
- // 通过驾车服务获取经纬度
- getPathByDrivingService(data) {
- const routes = data.routes;
- let pathes = [];
- /*routes.forEach(route => {
- route.steps.forEach(step => {
- step.path.forEach(path => {
- pathes.push([ path.lng, path.lat ]);
- });
- });
- });*/
- // 默认拿第一个路线
- routes[0].steps.forEach(step => {
- step.path.forEach(path => {
- pathes.push([path.lng, path.lat]);
- });
- });
- return pathes;
- },
- walkingService(location, walkingInstance, callback) {
- return new Promise(res => {
- walkingInstance.search(location[0], location[1], function (status, result) {
- if (status === 'complete') {
- // 使用服务返回的经纬度集合
- res(callback(result, true));
- } else {
- // 使用直连线
- res(callback(result, false));
- console.log('步行路线数据查询失败' + result);
- }
- });
- });
- },
- transferService(location, transferInstance, callback) {
- // 公交地铁
- return new Promise(res => {
- transferInstance.search(location[0], location[1], function (status, result) {
- if (status === 'complete') {
- // 使用服务返回的经纬度集合
- if (result.info && result.info.indexOf(ErrorAMapMsgModel.NO_DATA) >= 0) res(callback(result, false));
- else res(callback(result, true));
- } else {
- // 使用直连线
- res(callback(result, false));
- console.log(`公交路线数据查询失败:::${location}`);
- console.log(result);
- }
- });
- });
- },
- drivingService(location, drivingInstance, callback) {
- // 驾车
- return new Promise(res => {
- drivingInstance.search(location[0], location[1], function (status, result) {
- if (status === 'complete') {
- // 使用服务返回的经纬度集合
- res(callback(result, true));
- } else {
- // 使用直连线
- res(callback(result, false));
- console.log(`驾车路线数据查询失败:::${location}`);
- console.log(result);
- }
- });
- });
- },
- getData_API() {
- ToastService.loading({ message: '数据加载中...', forbidClick: false, getContainer: '#trajectory_map' });
- this.dataList = [];
- this.path = [];
- APIDevice.historyDetailListByIMEI({
- deviceid: this.$store.getters.serialNo,
- mapType: 'gaode',
- start: new Date(this.date).Format('yyyy-MM-dd'),
- end: new Date(this.date).Format('yyyy-MM-dd')
- })
- .then(result => {
- if (result.data.stateCode !== 1) {
- ToastService.clear();
- DialogService.confirm({ title: result.data.message });
- } else {
- // 2022.7. 8 修复 ios端 时间格式 - 不识别的问题,备注: 用正则将接口中时间格式替换成/
- let newData = result.data.data.item[0].map(item => {
- return {
- ...item,
- time: item.time.replace(new RegExp(/(-)/g), '/')
- };
- });
- const filterData = this.deduplicatedANDDecorateList(newData);
- console.log('filterData', filterData);
- const circleData = this.decorateListCircle(filterData);
- console.log('circleData', circleData);
- const speedData = this.decorateListSpeed(circleData);
- console.log('speedData', speedData);
- const filterSpeedData = this.calculateByContext(speedData);
- console.log('filterSpeedData:::', filterSpeedData);
- this.decoratedAddressList = this.decorateListAddress(filterSpeedData);
- this.resetMarker();
- this.clearMap();
- this.setAddressANDTime(filterData[0]);
- // todo 循环经算出各路径的出行方式,将连续 driving 的路径使用轨迹纠偏
- const serviceTypedData = this.serviceTypeFilter(filterSpeedData);
- const drivingFilterData = this.changeToDriving(serviceTypedData);
- console.log('drivingFilterData:::', drivingFilterData);
- this.createServiceV2(drivingFilterData);
- }
- })
- .catch(e => {
- console.log(e);
- })
- .finally(() => () => ToastService.clear());
- },
- async getMap() {
- ToastService.loading({ message: '地图加载中...', forbidClick: false, getContainer: '#trajectory_map' });
- let oldData,
- oldStateCode = 0;
- // 获取头像
- try {
- oldData = await this.getData();
- oldStateCode = oldData.data.stateCode;
- this.imagePath = oldData.data.imagePath;
- } catch (e) {
- ToastService.clear();
- }
- /*const oldData = await this.getData();
- let oldStateCode = 1;
- if (oldData.data.stateCode === 0) {
- oldStateCode = 0;
- }
- this.imagePath = oldData.data.imagePath;*/
-
- const plugins = [
- 'AMap.Geocoder',
- 'AMap.GraspRoad',
- 'AMap.GeometryUtil',
- 'AMap.CitySearch',
- 'AMap.Walking',
- 'AMap.Riding',
- 'AMap.Transfer',
- 'AMap.Driving',
- 'AMap.ToolBar'
- ];
- MapLoader(false, plugins).then(
- AMap => {
- // 地图实例
- this.map.instance = new AMap.Map('trajectory_map', {
- center: null,
- resizeEnable: true,
- zoom: this.map.zoom
- });
- if (process.env.NODE_ENV !== 'production') {
- const toolBar = new AMap.ToolBar({ offset: new AMap.Pixel(10, 400), position: 'LT' });
- this.map.instance.addControl(toolBar);
- }
-
- ToastService.clear();
- if (oldStateCode) {
- this.getData_API();
- }
- },
- e => {
- console.log('加载地图失败,下面是报错数据');
- console.log(e);
- }
- );
- },
-
- /* todo 轨迹纠偏 start */
- graspRoadService(locationList, drivingInstance, callback) {
- // 轨迹纠偏
- return new Promise(res => {
- drivingInstance.driving(locationList, function (error, result) {
- if (!error) {
- let path2 = [];
- let newPath = result.data.points;
- for (let i = 0; i < newPath.length; i++) {
- const location = [parseFloat(newPath[i].x.toFixed(6)), parseFloat(newPath[i].y.toFixed(6))];
- path2.push(location);
- }
- res(callback(newPath, true));
- } else {
- res(callback(result, false));
- console.log(`轨迹纠偏查询失败:::`, locationList);
- console.log(result);
- }
- });
- });
- },
- /* todo 轨迹纠偏 end */
-
- async createServiceV2(data) {
- ToastService.loading({ message: '正在加载...' });
- if (data.length === 0) {
- ToastService.clear();
- return;
- }
-
- let drivingCounts = 0; // 驾车路线的数量
- let wrongItemCounts = 0; // 调用了路线规划后验证此点不符合速度要求的点的数量
- for (let i = 0; i < data.length; i++) {
- if (i === 0) {
- this.path.push([data[i].lng, data[i].lat]);
- continue;
- }
- let preItem = data[i - 1 - wrongItemCounts];
- const item = data[i];
- let location = [
- [preItem.lng, preItem.lat],
- [item.lng, item.lat]
- ];
- let address = preItem.address;
- let timeDif = this.calculateTime(preItem.e_time, item.s_time);
-
- if (item.serviceType === this.serviceTypes.driving && i !== data.length - 1) {
- // 属于驾车时,累计驾车服务数量
- drivingCounts++;
- continue;
- } else {
- // 当终点服务类型为 非驾车 && drivingCounts > 0 时,调取轨迹纠偏
- // todo 轨迹纠偏
- if (drivingCounts > 0) {
- try {
- const start = i - drivingCounts - 1 - wrongItemCounts,
- end = i - 1;
- const locationList = this.getGraspServiceParamsReady(data, start, end);
- console.log(`共${drivingCounts + 1}项使用了轨迹纠偏:::start_${start}, end_${end}`);
- console.log(`start:::`, data[start]);
- console.log(`end:::`, data[end]);
- console.log(`轨迹纠偏参数:::`, locationList);
- this.serviceLog(preItem.serviceType, data[end]); // 打印 log
- // todo 轨迹纠偏的最后一个参数的 sp 需要归零
- if (locationList.length) {
- locationList[locationList.length - 1].sp = 0;
- }
- await this.graspRoadService(
- locationList,
- // eslint-disable-next-line
- new AMap.GraspRoad(),
- (result, useService) => {
- if (useService) {
- this.path = this.path.concat(
- result.map(item => {
- return [parseFloat(item.x.toFixed(6)), parseFloat(item.y.toFixed(6))];
- })
- );
- wrongItemCounts = 0;
- } else {
- this.addPathByStraight([item.lng, item.lat]);
- wrongItemCounts = 0;
- }
- }
- );
- } catch (e) {
- console.log('纠偏报错:::', e);
- }
- // 由于driving服务改为了轨迹纠偏,是累计方式,那么只有循环到非driving方式才调取轨迹纠偏
- // 所以其他服务需要用到的变量需要重新赋值
- preItem = data[i - 1];
- location = [
- [preItem.lng, preItem.lat],
- [item.lng, item.lat]
- ];
- address = preItem.address;
- timeDif = this.calculateTime(preItem.e_time, item.s_time);
- // 归零
- drivingCounts = 0;
- }
-
- this.serviceLog(item.serviceType, item); // 打印 log
-
- // todo 路径规划
- // 调取其他出行方式的路径规划服务
- const isSameAddress = this.checkAddress(address, item.address);
- if (
- item.serviceType === this.serviceTypes.overTime ||
- item.serviceType === this.serviceTypes.overSpeed ||
- isSameAddress ||
- (item.serviceType === this.serviceTypes.sameAddress && wrongItemCounts) ||
- item.serviceType === this.serviceTypes.transfer /* todo 高德暂无高铁服务,改为直连线 */
- ) {
- // 直连线:超时、超速、地址相同/包含
- if (i === 1) {
- this.path = this.path.concat(location);
- this.collectionStraightPoints = this.collectionStraightPoints.concat(location);
- continue;
- }
- let point = [item.lng, item.lat];
- this.path.push(point);
- this.collectionStraightPoints.push(point);
- wrongItemCounts = 0; // 归零
- drivingCounts = 0; // 归零
- continue;
- } else if (item.serviceType === this.serviceTypes.walking || item.serviceType === this.serviceTypes.riding) {
- // 步行、骑行
- await this.walkingService(
- location,
- // eslint-disable-next-line
- new AMap.Walking({ map: this.map.instance, autoFitView: i === data.length - 1, hideMarkers: true }),
- (result, useService) => {
- if (useService) {
- console.log(`服务返回路程:${result.routes[0].distance} 米`);
- if (this.checkSpeedByServiceType(result.routes[0].distance / timeDif, item.serviceType)) {
- this.path = this.path.concat(this.getPathByWalkingService(result));
- wrongItemCounts = 0;
- } else if (item.circle) {
- // 当前点为聚集点
- this.addPathByStraight([item.lng, item.lat]);
- wrongItemCounts = 0;
- console.log('上面的服务不符合,但为聚集点,直连');
- } else {
- wrongItemCounts++; // 保留起点
- item.skipService = true;
- console.log('上面的服务不符合,跳过');
- }
- } else {
- this.addPathByStraight([item.lng, item.lat]);
- wrongItemCounts = 0;
- console.log(`步行:::`, result);
- }
- }
- );
- // eslint-disable-next-line no-dupe-else-if
- } else if (item.serviceType === this.serviceTypes.transfer) {
- // 公交、地铁
- await this.transferService(
- location,
- // eslint-disable-next-line
- new AMap.Transfer({
- map: this.map.instance,
- autoFitView: i === data.length - 1,
- hideMarkers: true,
- city: preItem.cityCode,
- cityd: item.cityCode
- }),
- (result, useService) => {
- if (useService) {
- console.log(`服务返回路程:${result.plans[0].distance} 米`);
- if (this.checkSpeedByServiceType(result.plans[0].distance / timeDif, item.serviceType)) {
- this.path = this.path.concat(this.getPathByTransferService(result));
- wrongItemCounts = 0;
- } else if (item.circle) {
- // 当前点为聚集点
- this.addPathByStraight([item.lng, item.lat]);
- wrongItemCounts = 0;
- console.log('上面的服务不符合,但为聚集点,直连');
- } else {
- wrongItemCounts++; // 保留起点
- item.skipService = true;
- console.log('上面的服务不符合,跳过');
- }
- } else {
- this.addPathByStraight([item.lng, item.lat]);
- wrongItemCounts = 0;
- console.log(`公交:::`, result);
- }
- }
- );
- }
- }
- }
- // for() {} done
-
- console.log('path::::', this.path);
-
- ToastService.clear();
- this.clearMap();
- this.polylineList = this.path.map(item => item);
- this.createMarker(this.path);
- this.createPolyline(this.path);
- this.createCircles(data);
- },
- async createServiceV2New(data) {
- // 如果 已经绘制了新的轨迹 则把坐标数组清空 防止第二次以后绘制出现直连线的问题
- if (this.pathNew) {
- this.pathNew = [];
- }
- ToastService.loading({ message: '正在加载...' });
- if (data.length === 0) {
- ToastService.clear();
- return;
- }
-
- let drivingCounts = 0; // 驾车路线的数量
- let wrongItemCounts = 0; // 调用了路线规划后验证此点不符合速度要求的点的数量
- for (let i = 0; i < data.length; i++) {
- if (i === 0) {
- this.pathNew.push([data[i].lng, data[i].lat]);
- continue;
- }
- let preItem = data[i - 1 - wrongItemCounts];
- const item = data[i];
- let location = [
- [preItem.lng, preItem.lat],
- [item.lng, item.lat]
- ];
- let address = preItem.address;
- let timeDif = this.calculateTime(preItem.e_time, item.s_time);
-
- if (item.serviceType === this.serviceTypes.driving && i !== data.length - 1) {
- // 属于驾车时,累计驾车服务数量
- drivingCounts++;
- continue;
- } else {
- // 当终点服务类型为 非驾车 && drivingCounts > 0 时,调取轨迹纠偏
- // todo 轨迹纠偏
- if (drivingCounts > 0) {
- try {
- const start = i - drivingCounts - 1 - wrongItemCounts,
- end = i - 1;
- const locationList = this.getGraspServiceParamsReady(data, start, end);
- console.log(`共${drivingCounts + 1}项使用了轨迹纠偏:::start_${start}, end_${end}`);
- console.log(`start:::`, data[start]);
- console.log(`end:::`, data[end]);
- console.log(`轨迹纠偏参数:::`, locationList);
- this.serviceLog(preItem.serviceType, data[end]); // 打印 log
- // todo 轨迹纠偏的最后一个参数的 sp 需要归零
- if (locationList.length) {
- locationList[locationList.length - 1].sp = 0;
- }
- await this.graspRoadService(
- locationList,
- // eslint-disable-next-line
- new AMap.GraspRoad(),
- (result, useService) => {
- if (useService) {
- this.pathNew = this.pathNew.concat(
- result.map(item => {
- return [parseFloat(item.x.toFixed(6)), parseFloat(item.y.toFixed(6))];
- })
- );
- wrongItemCounts = 0;
- } else {
- this.addPathByStraight([item.lng, item.lat]);
- wrongItemCounts = 0;
- }
- }
- );
- } catch (e) {
- console.log('纠偏报错:::', e);
- }
- // 由于driving服务改为了轨迹纠偏,是累计方式,那么只有循环到非driving方式才调取轨迹纠偏
- // 所以其他服务需要用到的变量需要重新赋值
- preItem = data[i - 1];
- location = [
- [preItem.lng, preItem.lat],
- [item.lng, item.lat]
- ];
- address = preItem.address;
- timeDif = this.calculateTime(preItem.e_time, item.s_time);
- // 归零
- drivingCounts = 0;
- }
-
- this.serviceLog(item.serviceType, item); // 打印 log
-
- // todo 路径规划
- // 调取其他出行方式的路径规划服务
- const isSameAddress = this.checkAddress(address, item.address);
- if (
- item.serviceType === this.serviceTypes.overTime ||
- item.serviceType === this.serviceTypes.overSpeed ||
- isSameAddress ||
- (item.serviceType === this.serviceTypes.sameAddress && wrongItemCounts) ||
- item.serviceType === this.serviceTypes.transfer /* todo 高德暂无高铁服务,改为直连线 */
- ) {
- // 直连线:超时、超速、地址相同/包含
- if (i === 1) {
- this.pathNew = this.pathNew.concat(location);
- this.collectionStraightPointsNew = this.collectionStraightPointsNew.concat(location);
- continue;
- }
- let point = [item.lng, item.lat];
- this.pathNew.push(point);
- this.collectionStraightPointsNew.push(point);
- wrongItemCounts = 0; // 归零
- drivingCounts = 0; // 归零
- continue;
- } else if (item.serviceType === this.serviceTypes.walking || item.serviceType === this.serviceTypes.riding) {
- // 步行、骑行
- await this.walkingService(
- location,
- // eslint-disable-next-line
- new AMap.Walking({ map: this.map.instance, autoFitView: i === data.length - 1, hideMarkers: true }),
- (result, useService) => {
- if (useService) {
- console.log(`服务返回路程:${result.routes[0].distance} 米`);
- if (this.checkSpeedByServiceType(result.routes[0].distance / timeDif, item.serviceType)) {
- this.pathNew = this.pathNew.concat(this.getPathByWalkingService(result));
- wrongItemCounts = 0;
- } else if (item.circle) {
- // 当前点为聚集点
- this.addPathByStraight([item.lng, item.lat]);
- wrongItemCounts = 0;
- console.log('上面的服务不符合,但为聚集点,直连');
- } else {
- wrongItemCounts++; // 保留起点
- item.skipService = true;
- console.log('上面的服务不符合,跳过');
- }
- } else {
- this.addPathByStraight([item.lng, item.lat]);
- wrongItemCounts = 0;
- console.log(`步行:::`, result);
- }
- }
- );
- // eslint-disable-next-line no-dupe-else-if
- } else if (item.serviceType === this.serviceTypes.transfer) {
- // 公交、地铁
- await this.transferService(
- location,
- // eslint-disable-next-line
- new AMap.Transfer({
- map: this.map.instance,
- autoFitView: i === data.length - 1,
- hideMarkers: true,
- city: preItem.cityCode,
- cityd: item.cityCode
- }),
- (result, useService) => {
- if (useService) {
- console.log(`服务返回路程:${result.plans[0].distance} 米`);
- if (this.checkSpeedByServiceType(result.plans[0].distance / timeDif, item.serviceType)) {
- this.pathNew = this.pathNew.concat(this.getPathByTransferService(result));
- wrongItemCounts = 0;
- } else if (item.circle) {
- // 当前点为聚集点
- this.addPathByStraight([item.lng, item.lat]);
- wrongItemCounts = 0;
- console.log('上面的服务不符合,但为聚集点,直连');
- } else {
- wrongItemCounts++; // 保留起点
- item.skipService = true;
- console.log('上面的服务不符合,跳过');
- }
- } else {
- this.addPathByStraight([item.lng, item.lat]);
- wrongItemCounts = 0;
- console.log(`公交:::`, result);
- }
- }
- );
- }
- }
- }
- // for() {} done
- ToastService.clear();
- this.resetMarkerNew();
- this.polylineList = this.pathNew.map(item => item);
- this.createMarkerNew(this.pathNew);
- this.createPolylineNew(this.pathNew);
- this.createCirclesNew(data);
- },
- // 组装轨迹纠偏参数
- getGraspServiceParamsReady(data, start, end) {
- const tm0 = Math.round(new Date(data[start].s_time).getTime() / 1000);
- return data.slice(start, end + 1).map((item, i) => {
- const tmI = Math.round(new Date(item.e_time).getTime() / 1000) - tm0;
- return {
- x: item.lng,
- y: item.lat,
- sp: item.sp,
- ag: 0,
- tm: i === 0 ? tm0 : tmI
- };
- });
- },
- serviceLog(type, item) {
- console.log(`服务::::${type}`);
- console.log('终点::::', item);
- console.count('------------------');
- },
- // 验证路径规划服务的结果是否符合情景
- // 根据服务结果计算出的速度是否符合设定的区间
- checkSpeedByServiceType(sp, type) {
- sp = sp * this.ms_TO_kmh; // m/s 转 km/h
- let result = true;
- switch (type) {
- case 'walking':
- case 'riding':
- result = sp <= this.speedTypes.riding[1];
- break;
- case 'driving':
- result = sp <= this.speedTypes.driving[1] && sp > this.speedTypes.driving[0];
- break;
- case 'transfer':
- result = sp <= this.speedTypes.highRailway[1] && sp >= this.speedTypes.highRailway[0];
- break;
- }
- if (!result) console.log(`服务返回速度结果不符合预设区间,服务类型:${type},速度:${sp} km/h`);
- return result;
- },
- // 检查中文地址是否相同、包含
- checkAddress(addA, addB) {
- return addA === addB || addA.indexOf(addB) >= 0 || addB.indexOf(addA) >= 0;
- },
- addPathByStraight(destinationLngLat) {
- this.path.push(destinationLngLat);
- this.collectionStraightPoints.push(destinationLngLat);
- },
- // 清除地图的覆盖物
- clearMap() {
- this.map.instance.clearMap();
- },
- resetMarker() {
- this.map.marker = {};
- this.map.polyline = {};
- this.map.passedPolyline = {};
- },
- resetMarkerNew() {
- this.map.marker = {};
- this.map.polylineNew = {};
- this.map.passedPolylineNew = {};
- },
- assemblePolylineList(lngLatList) {
- this.polylineList = lngLatList.map(item => item);
- },
- createCircles(dataList) {
- dataList.forEach((item, i) => {
- if (i === dataList.length - 1) {
- let center = [item.lng, item.lat];
- // eslint-disable-next-line
- let circle = new AMap.Circle({
- center,
- radius: this.limitDistance, // 半径
- borderWeight: 3,
- strokeColor: '#2599ff',
- strokeWeight: 4,
- strokeOpacity: 0.4,
- fillOpacity: 0.2,
- fillColor: '#2599ff',
- zIndex: 10
- });
- circle.setMap(this.map.instance);
- this.circleList.push(circle);
- return;
- }
- if (item.circle /* && !item.skipService*/) {
- let center = [item.lng, item.lat];
- // eslint-disable-next-line
- let circle = new AMap.Circle({
- center,
- radius: this.limitDistance, // 半径
- borderWeight: 3,
- strokeColor: '#fa796e',
- strokeWeight: 4,
- strokeOpacity: 0.4,
- fillOpacity: 0.2,
- // fillColor: "#2599ff",
- fillColor: '#fa796e',
- zIndex: 10
- });
- circle.setMap(this.map.instance);
- this.circleList.push(circle);
- }
- });
- },
- createCirclesNew(dataList) {
- dataList.forEach((item, i) => {
- if (i === dataList.length - 1) {
- let center = [item.lng, item.lat];
- // eslint-disable-next-line
- let circle = new AMap.Circle({
- center,
- radius: this.limitDistance, // 半径
- borderWeight: 3,
- strokeColor: '#2599ff',
- strokeWeight: 4,
- strokeOpacity: 0.4,
- fillOpacity: 0.2,
- fillColor: '#2599ff',
- zIndex: 10
- });
- circle.setMap(this.map.instance);
- this.circleListNew.push(circle);
- return;
- }
- if (item.circle /* && !item.skipService*/) {
- let center = [item.lng, item.lat];
- // eslint-disable-next-line
- let circle = new AMap.Circle({
- center,
- radius: this.limitDistance, // 半径
- borderWeight: 3,
- strokeColor: '#fa796e',
- strokeWeight: 4,
- strokeOpacity: 0.4,
- fillOpacity: 0.2,
- // fillColor: "#2599ff",
- fillColor: '#fa796e',
- zIndex: 10
- });
- circle.setMap(this.map.instance);
- this.circleListNew.push(circle);
- }
- });
- },
- createMarker(dataList) {
- let center;
- if (dataList[0].lng && dataList[0].lat) {
- center = [dataList[0].lng, dataList[0].lat];
- } else {
- center = [dataList[0][0], dataList[0][1]];
- }
- let content = `<div class="imageArea">
- <img class="image_area" src="${this.imagePath}" />
- <em></em>
- </div>`;
- /*let content = `<div class="img">
- <div class="image_area">
- <img src="${this.imagePath}" />
- <i></i>
- </div>
- <div class="circel"></div>
- </div>`;*/
- // eslint-disable-next-line no-undef
- this.map.marker = new AMap.Marker({ position: center, content, offset: new AMap.Pixel(-29, -76) });
- this.map.instance.add(this.map.marker);
- this.map.instance.setCenter(center);
- },
- createMarkerNew(dataList) {
- let center;
- if (dataList[0].lng && dataList[0].lat) {
- center = [dataList[0].lng, dataList[0].lat];
- } else {
- center = [dataList[0][0], dataList[0][1]];
- }
- let content = `<div class="imageArea">
- <img class="image_area" src="${this.imagePath}" />
- <em></em>
- </div>`;
- /*let content = `<div class="img">
- <div class="image_area">
- <img src="${this.imagePath}" />
- <i></i>
- </div>
- <div class="circel"></div>
- </div>`;*/
- // eslint-disable-next-line no-undef
- this.map.marker = new AMap.Marker({ position: center, content, offset: new AMap.Pixel(-58, -152) });
- this.map.instance.add(this.map.marker);
- this.map.instance.setCenter(center);
- },
- createPolyline(lngLatList) {
- const data = lngLatList.map(item => item);
- // eslint-disable-next-line
- this.map.polyline = new AMap.Polyline({
- map: this.map.instance,
- path: data,
- strokeColor: '#43598a', //线颜色
- strokeOpacity: 0.8, //线透明度
- strokeWeight: 12, //线宽
- // strokeStyle: "solid", //线样式
- lineJoin: 'round',
- lineCap: 'round',
- showDir: true,
- geodesic: true
- });
- // eslint-disable-next-line
- this.map.passedPolyline = new AMap.Polyline({
- map: this.map.instance,
- strokeColor: '#ffc554', //线颜色
- strokeOpacity: 0.9, //线透明度
- strokeWeight: 10, //线宽
- lineJoin: 'round',
- lineCap: 'round',
- showDir: true,
- geodesic: true
- });
-
- let start_idx = 0;
- this.map.marker.on('moving', e => {
- try {
- this.map.passedPolyline.setPath(e.passedPath);
- this.lngLatOnMoving = e.passedPath.map(o => {
- return [o.lng, o.lat];
- });
- if (start_idx >= this.dataList.length) return;
- const length = this.lngLatOnMoving.length;
- const radius = 40; // 距离条件
- const idx = start_idx - 1 < 0 ? start_idx : start_idx - 1;
- const circleCenterLngLat = [this.dataList[idx].lng, this.dataList[idx].lat];
- const isLess = this.checkDistanceLessThanRadius(circleCenterLngLat, this.lngLatOnMoving[length - 1], radius);
- if (!isLess) {
- this.setAddressANDTime(this.dataList[idx]);
- } else {
- start_idx++;
- this.setAddressANDTime(this.dataList[start_idx]);
- }
- } catch (e) {
- console.log('fail::moving::::', e);
- }
- });
- },
- // 绘制 一条对比的轨迹
- createPolylineNew(lngLatList) {
- console.log('lngLatList', lngLatList);
- const data = lngLatList.map(item => item);
- console.log('data', data);
- // eslint-disable-next-line
- this.map.polylineNew = new AMap.Polyline({
- map: this.map.instance,
- path: data,
- strokeColor: 'red', //线颜色
- strokeOpacity: 0.8, //线透明度
- strokeWeight: 12, //线宽
- // strokeStyle: "solid", //线样式
- lineJoin: 'round',
- lineCap: 'round',
- showDir: true,
- geodesic: true
- });
- // eslint-disable-next-line
- this.map.passedPolylineNew = new AMap.Polyline({
- map: this.map.instance,
- strokeColor: '#ffc554', //线颜色
- strokeOpacity: 0.9, //线透明度
- strokeWeight: 10, //线宽
- lineJoin: 'round',
- lineCap: 'round',
- showDir: true,
- geodesic: true
- });
-
- let start_idx = 0;
- this.map.marker.on('moving', e => {
- try {
- this.map.passedPolylineNew.setPath(e.passedPath);
- this.lngLatOnMovingNew = e.passedPath.map(o => {
- return [o.lng, o.lat];
- });
- if (start_idx >= this.dataListNew.length) return;
- const length = this.lngLatOnMovingNew.length;
- const radius = 40; // 距离条件
- const idx = start_idx - 1 < 0 ? start_idx : start_idx - 1;
- const circleCenterLngLat = [this.dataListNew[idx].lng, this.dataListNew[idx].lat];
- const isLess = this.checkDistanceLessThanRadius(
- circleCenterLngLat,
- this.lngLatOnMovingNew[length - 1],
- radius
- );
- if (!isLess) {
- this.setAddressANDTime(this.dataListNew[idx]);
- } else {
- start_idx++;
- this.setAddressANDTime(this.dataListNew[start_idx]);
- }
- } catch (e) {
- console.log('fail::moving::::', e);
- }
- });
- },
- // 比较两点的距离是否小于半径
- checkDistanceLessThanRadius(circleCenterLngLat, targetLngLat, radius) {
- // eslint-disable-next-line no-undef
- const distance = parseInt(AMap.GeometryUtil.distance(circleCenterLngLat, targetLngLat));
- return radius - distance > 0;
- },
- setAddressANDTime(o) {
- if (this.$own.isNotNull(o)) {
- this.address = o.address;
- this.time = o.time;
- }
- },
- toggleBottom(bool) {
- this.bottomContentShow = bool;
- },
-
- // 旧版本 start
- getData() {
- return new Promise((resolve, reject) => {
- /* let url = `/api/Location/History`;
- let jsonData = {
- deviceId: this.$store.getters.deviceId,
- dateTime: new Date(this.date),
- mapType: "gaode",
- timeOffset: -new Date().getTimezoneOffset() / 60
- }; */
- /* this.$axios
- .post(url, jsonData) */
- APIDevice.history({
- deviceId: this.$store.getters.deviceId,
- dateTime: new Date(this.date),
- mapType: 'gaode',
- timeOffset: -new Date().getTimezoneOffset() / 60
- })
- .then(res => {
- resolve(res);
- if (res.data.stateCode === 0 && res.data.list == null) {
- DialogService.confirm({ title: res.data.message /* className: 'device_confirm' */ });
- ToastService.clear();
- }
- })
- .catch(err => {
- reject(err);
- // Dialog({ title: '您的网络异常', message: '请稍后重试', className: 'device_confirm' });
- })
- .finally(() => (this.showOverlay = false));
- });
- },
- // 旧版本 end
-
- //逆地理编码
- geocoder(value, type) {
- //value是坐标(数组) type传入的boolean
- let that = this;
-
- new Promise((resolve, reject) => {
- let MGeocoder = null;
- let obj = {};
- that.map.plugin(['AMap.Geocoder'], () => {
- // eslint-disable-next-line no-undef
- MGeocoder = new AMap.Geocoder({
- radius: 1000,
- extensions: 'all'
- });
-
- MGeocoder.getAddress(value, (status, result) => {
- if (status == 'complete' && result.info == 'OK') {
- let address = result.regeocode.formattedAddress;
- obj = { address };
- resolve(obj);
- } else {
- reject(obj);
- }
- });
- });
- })
- .then(res => {
- if (type) return true;
- that.bottomContentShow = true;
- that.address = res.address;
- })
- .catch(err => {
- // that.bottomContentShow = false;
- that.address = '无效的地理位置';
- console.log(err);
- if (type) {
- return false;
- } else {
- console.log('坐标参数错误');
- // that.dialog("坐标参数错误");
- }
- });
- },
- playerControl() {
- this.playFlag = !this.playFlag;
- if (this.playFlag) {
- this.num = 0;
- this.marker.moveAlong(this.lineArr, this.leftCode);
- console.log('开始了!');
- } else {
- this.marker.pauseMove();
- console.log('暂停了!再次点击将重来');
- }
- },
- dateClick(type) {
- this.playFlag = false;
- this.calendarShow = false;
- this.initTime();
- if (type == 'add' && this.clickFlag) {
- if (this.count >= 0) {
- return;
- }
- this.count++;
- this.date = this.$own.getNowFormatDate(this.count);
- this.handleMinDate(this.date);
- this.defaultDate = new Date(this.date.replace(/-/g, '/'));
- // this.getData();
- // this.getAmap();
- this.getData_API();
- } else {
- if (this.clickFlag) {
- this.count--;
- this.date = this.$own.getNowFormatDate(this.count);
- this.handleMinDate(this.date);
- this.defaultDate = new Date(this.date.replace(/-/g, '/'));
- // this.getData();
- // this.getAmap();
- this.getData_API();
- }
- }
- },
- handleMinDate() {
- /* let getYear = new Date(date).getFullYear();
- let getMonth = new Date(date).getMonth(); */
- // TODO #BUG 取消点击选择日期时最小日期自动变化
- /* this.minDate = new Date(getYear, getMonth, 1); */
- },
- dateAreaClick() {
- this.calendarShow = !this.calendarShow;
- },
- onSelect(val) {
- this.date = new Date(val).Format('yyyy-MM-dd');
- this.handleMinDate(val);
- let nowTime = new Date(new Date().Format('yyyy-MM-dd')).getTime();
- let newTime = new Date(this.date).getTime();
- this.count = (newTime - nowTime) / (60 * 60 * 24 * 1000);
- this.calendarShow = false;
- this.initTime();
- this.closeTimePicker();
- // this.getData();
- // this.getAmap();
- this.getData_API();
- },
- // 根据时间端选择轨迹
- historyDetailListByIMEI() {
- ToastService.loading({
- message: '数据加载中...',
- forbidClick: false,
- getContainer: '#trajectory_map'
- });
- this.dataList = [];
- this.path = [];
- let date = new Date(this.date).Format('yyyy-MM-dd');
- let startTime = date + ' ' + this.initTimePick.initStartTime;
- let endTime = date + ' ' + this.initTimePick.initEndTime;
- APIDevice.historyDetailListByIMEI({
- deviceid: this.$store.getters.serialNo,
- mapType: 'gaode',
- start: startTime,
- end: endTime
- })
- .then(result => {
- if (result.data.stateCode !== 1) {
- ToastService.clear();
- DialogService.confirm({ title: result.data.message });
- } else {
- const filterData = this.deduplicatedANDDecorateList(result.data.data.item[0]);
- console.log('filterData', filterData);
- const circleData = this.decorateListCircle(filterData);
- console.log('circleData', circleData);
- const speedData = this.decorateListSpeed(circleData);
- console.log('speedData', speedData);
- const filterSpeedData = this.calculateByContext(speedData);
- console.log('filterSpeedData:::', filterSpeedData);
- this.decoratedAddressList = this.decorateListAddress(filterSpeedData);
- this.resetMarker();
- this.clearMap();
- this.setAddressANDTime(filterData[0]);
- // todo 循环经算出各路径的出行方式,将连续 driving 的路径使用轨迹纠偏
- const serviceTypedData = this.serviceTypeFilter(filterSpeedData);
- const drivingFilterData = this.changeToDriving(serviceTypedData);
- console.log('drivingFilterData:::', drivingFilterData);
- this.createServiceV2(drivingFilterData);
- }
- })
- .catch(e => {
- console.log('错误::', e);
- ToastService.clear();
- })
- .finally(() => {
- ToastService.clear();
- });
- },
- // 点击'时间'快捷方式
- onTimeClick() {
- console.log('点击了时间');
- this.timePickWidth = 80;
- this.timeWidth = 20;
- this.isLeft = false;
- this.isPopup = !this.isPopup;
- if (!this.isPopup) {
- this.timePickWidth = 20;
- this.timeWidth = 100;
- this.isLeft = true;
- }
- },
- // 点击开始时间
- onStartClick() {
- this.timePickData.timePickStartShow = !this.timePickData.timePickStartShow;
- this.timePickData.timePickEndShow = false;
- this.calendarShow = false;
- },
- // 点击结束时间
- onEndClick() {
- this.timePickData.timePickEndShow = !this.timePickData.timePickEndShow;
- this.timePickData.timePickStartShow = false;
- this.calendarShow = false;
- },
- // 点击确认开始时间
- onStartTimeConfirm(startTime) {
- this.initTimePick.initStartTime = startTime;
- console.log('startTime', startTime);
- this.onCloseTimePicker();
- },
- // 点击取消开始时间
- onStartTimeCancel() {
- this.timePickData.timePickStartShow = false;
- },
- // 点击确认结束时间
- onEndTimeConfirm(endTime) {
- this.initTimePick.initEndTime = endTime;
- console.log('结束时间', endTime);
- this.timePickData.timePickEndShow = false;
- },
- // 点击取消结束时间
- onEndTimeCancel() {
- this.timePickData.timePickEndShow = false;
- },
- // 关闭开始时间选择器,开始结束时间选择器
- onCloseTimePicker() {
- this.timePickData.timePickStartShow = false;
- this.timePickData.timePickEndShow = true;
- },
- // 查看轨迹
- onConfirm() {
- this.closeTimePicker();
- this.historyDetailListByIMEI();
- },
- // // 关闭时间选择器
- closeTimePicker() {
- this.timePickWidth = 20;
- this.timeWidth = 80;
- this.isLeft = false;
- this.isPopup = false;
- },
- // 初始化时间选择器的时间
- initTime() {
- this.initTimePick.initStartTime = '00:00';
- this.initTimePick.initEndTime = '23:59';
- this.timePickData.selectStartTime = '00:00'; //初始化选择器内的时间
- this.timePickData.selecttEndTime = '23:59';
- },
- // 判断字符串是否可以转化为json数据
- isJsonString(str) {
- try {
- if (typeof JSON.parse(str) == 'object') {
- return true;
- }
- } catch (e) {
- /* empty */
- }
- return false;
- },
- onDialogCancel() {
- this.dialogInput = '';
- }
- }
- };
- </script>
-
- <style lang="scss">
- @import './trajectory.scss';
- .player {
- i {
- color: #fff;
- }
- }
-
- .img {
- position: relative;
- height: 84px;
- display: flex;
- flex-flow: column;
- justify-content: flex-start;
- align-items: center;
- border-radius: 50%;
- z-index: 3;
- }
-
- .img .circel {
- position: absolute;
- bottom: 0;
- width: 90px;
- height: 90px;
- /*background: rgba(255, 150, 37, 0.2);*/
- border-radius: 50%;
- display: flex;
- justify-content: center;
- align-items: center;
- }
-
- .img .circel:before {
- content: '';
- position: absolute;
- width: 30px;
- height: 30px;
- background: #fff;
- border-radius: 50%;
- z-index: 3;
- }
-
- .img .circel:after {
- content: ' ';
- position: absolute;
- width: 24px;
- height: 24px;
- background: #ff9625;
- border-radius: 50%;
- z-index: 4;
- }
-
- .img .image_area {
- position: relative;
- width: 92px;
- height: 92px;
- border-radius: 50%;
- background: #fff;
- display: flex;
- justify-content: center;
- align-items: center;
- z-index: 4;
- }
-
- .img .image_area:after {
- content: '';
- position: absolute;
- bottom: -10px;
- width: 0;
- height: 0;
- border-top: 12px solid #fff;
- border-left: 10px solid transparent;
- border-right: 10px solid transparent;
- }
-
- .img .image_area img {
- width: 84px;
- height: 84px;
- border-radius: 50%;
- object-fit: cover;
- }
-
- .img.online .image_area:after {
- border-top-color: #5fcc0e;
- }
-
- .img.online .image_area {
- background: #5fcc0e;
- }
-
- .img.unline .image_area:after {
- border-top-color: #b5b5b5;
- }
-
- .img.unline .image_area {
- background: #b5b5b5;
- }
-
- .imageArea {
- position: relative;
- display: flex;
- flex-flow: column;
- justify-content: center;
- align-items: center;
- width: 60px;
- height: 80px;
- background: url(../../assets/img/tooltip-sizing.png);
- }
-
- .imageArea img {
- position: absolute;
- top: 17px;
- width: 84px;
- height: 84px;
- border-radius: 50%;
- background: rgb(197, 94, 47);
- object-fit: cover;
- }
-
- .imageArea em {
- position: absolute;
- top: 128px;
- display: flex;
- justify-content: center;
- align-items: center;
- width: 30px;
- height: 30px;
- background: #fff;
- border-radius: 50%;
- }
-
- .imageArea em:after {
- content: ' ';
- width: 24px;
- height: 24px;
- background: #ff9625;
- border-radius: 50%;
- }
-
- .circleArea {
- width: 80px;
- height: 80px;
- background: rgba(37, 153, 255, 0.3);
- border-radius: 50%;
- display: flex;
- justify-content: center;
- align-items: center;
- }
-
- .circleArea i {
- display: flex;
- justify-content: center;
- align-items: center;
- width: 30px;
- height: 30px;
- background: #fff;
- border-radius: 50%;
- }
-
- .circleArea i:after {
- content: ' ';
- width: 24px;
- height: 24px;
- background: #2599ff;
- border-radius: 50%;
- }
-
- .c {
- width: 14px;
- height: 14px;
- border: 3px solid #3296fa;
- border-radius: 50%;
- background: #fff;
- display: flex;
- justify-content: center;
- align-items: center;
- }
-
- .c:before {
- content: '';
- width: 10px;
- height: 10px;
- background: #3296fa;
- border-radius: 50%;
- }
-
- .end {
- width: 50px;
- height: 50px;
- background-color: #ff0;
- background: transparent url(../../assets/icon.png) no-repeat;
- background-size: 400px 400px;
- background-position: -250px -150px;
- }
-
- .trajectory {
- height: 100vh;
- position: relative;
- overflow: hidden;
- .trajectory-con {
- position: relative;
- /* height: calc(100vh - 100px); */
- overflow: scroll;
- .top {
- width: 100%;
- position: absolute;
- left: 0;
- top: 0;
- z-index: 999;
- background: #fff;
-
- .dateArea {
- padding: 0 30px;
- height: 100px;
- display: flex;
- justify-content: space-between;
- align-items: center;
- z-index: 999;
- i {
- @include center();
- width: 62px;
- height: 62px;
- border-radius: 50%;
- background: rgba(207, 207, 207, 0.36);
-
- &:before {
- content: '';
- width: 50px;
- height: 50px;
- @include icon();
- @include icon_position(50, 50, 100, 0);
- }
-
- &.right {
- &:before {
- @include icon_position(50, 50, 100, 50);
- }
-
- &.active {
- background: #c8e5ff;
-
- &:before {
- transform: rotate(180deg);
- @include icon_position(50, 50, 100, 0);
- }
- }
- }
-
- &.active {
- background: #c8e5ff;
- }
- }
-
- span {
- @include colorAndFont(#2599ff, 36);
- @include center();
-
- &:after {
- content: '';
- margin: 6px 0 0 8px;
- width: 0;
- height: 0;
- border-top: 12px solid $blue;
- border-left: 13px solid transparent;
- border-right: 13px solid transparent;
- border-radius: 10px;
- }
- }
- }
- }
- // 时间段选择项
- .time-picker {
- position: absolute;
- right: -20px;
- top: 250px;
- height: 80px;
- display: flex;
- justify-content: flex-start;
- background-color: #ffff;
- border-radius: 10px;
- box-shadow: 0 0 10px rgba(185, 185, 185, 0.9);
- z-index: 99;
- .time-picker-left {
- height: 80px;
- width: 30%;
- line-height: 60px;
- .van-icon-arrow-left,
- .van-icon-arrow {
- height: 10px;
- width: 20px;
- line-height: 40px;
- font-size: 14px;
- }
- span {
- font-size: 32px;
- }
- }
- .time-picker-right {
- height: 80px;
- width: 50%;
- line-height: 70px;
- text-align: center;
- span,
- label {
- font-size: 32px;
- }
- span {
- color: #2599ff;
- }
- label {
- padding: 10px;
- }
- }
- .datetimePicker {
- position: relative;
- top: 8px;
- right: 120px;
- width: 580px;
- }
- .time-picker-right-confirm {
- height: 80px;
- width: auto;
- display: flex;
- justify-content: center;
- align-items: center;
- line-height: 80px;
- text-align: center;
- padding-right: 20px;
- color: white;
-
- .right-confirm-text {
- height: 60px;
- width: 120px;
- line-height: 50px;
- background-color: #2599ff;
- border-radius: 10px;
- span {
- font-size: 32px;
- }
- }
- }
- }
- // 添加轨迹对比
- .bottom {
- width: 100%;
- position: fixed;
- left: 0;
- bottom: 0;
- z-index: 600;
- box-shadow: 0 0 20px rgba(185, 185, 185, 0.4);
-
- .conArea {
- position: relative;
- }
-
- .con {
- padding: 20px;
- background: #fff;
- border-radius: 24px 24px 0 0;
- .content-list {
- min-height: 100px;
- max-height: 200px;
- overflow: scroll;
- padding: 30px 0 0 30px;
- .content-item {
- margin-bottom: 10px;
- }
- }
-
- .title {
- width: 580px;
- @include colorAndFont(#333, 34);
- /*margin-bottom: px2rem(36);*/
- }
-
- .adr {
- @include colorAndFont(#999, 28);
- margin-bottom: px2rem(18);
-
- span {
- margin-left: 15px;
- padding: 0 8px;
- height: 30px;
- @include colorAndFont(#999, 20);
- background: #fafafa;
- border: 1px solid #b5b5b5;
- border-radius: 4px;
- }
- }
-
- .states {
- display: flex;
- justify-content: flex-start;
- align-items: center;
- span {
- display: flex;
- justify-content: flex-start;
- align-items: center;
- @include colorAndFont(#999, 24);
- }
- }
- }
-
- .player {
- position: absolute;
- right: 40px;
- top: 50%;
- margin-top: -42px;
- width: 84px;
- height: 84px;
- background: $blue;
- border-radius: 50%;
- box-shadow: 0 0 30px rgba(37, 153, 255, 0.4);
- @include center();
-
- i.play-icon {
- position: relative;
- width: 50px;
- height: 50px;
- @include center;
- @include icon();
- @include icon_position(50, 50, 100, 100);
- &.stop {
- background: unset;
- &:before,
- &:after {
- content: '';
- width: 8px;
- height: 32px;
- background-color: #fff;
- border-radius: 4px;
- }
- &:before {
- margin-right: 14px;
- }
- }
- }
- }
- }
-
- .slider-bar {
- position: absolute;
- right: 30px;
- top: -450px;
- padding: 60px 10px;
- width: 60px;
- height: 300px;
- background-color: #fff;
- border-radius: 10px;
- @include center();
- flex-flow: column;
- @include colorAndFont(#666, 16);
-
- .bar {
- height: 100%;
- margin: 20px 0;
- }
- .van-slider__button {
- width: 30px;
- height: 30px;
- }
- span {
- font-size: 20px;
- }
- }
- }
- }
- </style>
|