|
@@ -0,0 +1,263 @@
|
|
|
+/** // author:jiana // time:2025-04-23 // desc:运单管理 */
|
|
|
+<template>
|
|
|
+ <div class="mapMark">
|
|
|
+ <div class="btnBox">
|
|
|
+ <el-form :model="form" :rules="rules" label-width="auto">
|
|
|
+ <el-row>
|
|
|
+ <el-col :span="4">
|
|
|
+ <!-- 车牌号 -->
|
|
|
+ <el-form-item label="车牌号" prop="licensePlateNo">
|
|
|
+ <el-autocomplete
|
|
|
+ v-model="form.licensePlateNo"
|
|
|
+ :fetch-suggestions="querySearch"
|
|
|
+ clearable
|
|
|
+ placeholder="请输入车牌号"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="4">
|
|
|
+ <!-- 车牌颜色 -->
|
|
|
+ <el-form-item label="车牌颜色" prop="licensePlateColor">
|
|
|
+ <el-select clearable v-model="form.licensePlateColor" placeholder="请选择车牌颜色">
|
|
|
+ <el-option
|
|
|
+ v-for="item in licensePlateColorList"
|
|
|
+ :key="item.value"
|
|
|
+ :label="item.label"
|
|
|
+ :value="item.value"
|
|
|
+ ></el-option>
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <!-- 时间范围 -->
|
|
|
+ <!-- 限制结束时间在开始时间三天内 -->
|
|
|
+ <el-form-item label="时间范围" prop="timeRange">
|
|
|
+ <el-date-picker
|
|
|
+ clearable
|
|
|
+ v-model="form.startTime"
|
|
|
+ type="datetime"
|
|
|
+ placeholder="开始日期"
|
|
|
+ value-format="YYYY-MM-DD HH:mm:ss"
|
|
|
+ ></el-date-picker>
|
|
|
+ <el-date-picker
|
|
|
+ clearable
|
|
|
+ v-model="form.endTime"
|
|
|
+ :disabled-date="disabledDateFn"
|
|
|
+ type="datetime"
|
|
|
+ placeholder="结束日期"
|
|
|
+ value-format="YYYY-MM-DD HH:mm:ss"
|
|
|
+ ></el-date-picker>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="6">
|
|
|
+ <!-- 查询按钮 -->
|
|
|
+ <el-form-item>
|
|
|
+ <el-button type="primary" @click="queryWaybill">查询轨迹</el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+ <!-- 异常停留 -->
|
|
|
+ <div class="abnormal">
|
|
|
+ <div>
|
|
|
+ <span class="abnormal-title">共停留{{ parkArray.length }}次,共停留{{ totalMin }}分钟</span>
|
|
|
+ <el-button size="small" type="primary" @click="showTable = !showTable">查看停留明细</el-button>
|
|
|
+ </div>
|
|
|
+ <el-table :data="parkArray" style="width: 100%" border stripe size="small" v-if="showTable">
|
|
|
+ <el-table-column prop="parkBte" label="停留开始" width="180">
|
|
|
+ <template #default="scope">
|
|
|
+ {{ moment(Number(scope.row.parkBte)).format('yyyy-MM-DD hh:mm:ss') }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="parkMins" label="停留时长(分钟)" width="180"></el-table-column>
|
|
|
+ <el-table-column prop="parkAdr" label="停留地址"></el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+ <div id="container3"></div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+<script setup>
|
|
|
+import { defineComponent, ref, reactive, onMounted } from 'vue'
|
|
|
+import { useRoute } from 'vue-router'
|
|
|
+import AMapLoader from '@amap/amap-jsapi-loader'
|
|
|
+import { tms } from '@/request/api'
|
|
|
+import { Message, Modal, Spin } from 'view-ui-plus'
|
|
|
+import { transformFromWGSToGCJArr } from '../trackManager/utils.js'
|
|
|
+
|
|
|
+// 限制选择的结束时间必须在选择的开始时间后的三天内
|
|
|
+const disabledDateFn = time => {
|
|
|
+ const startTime = new Date(form.value.startTime)
|
|
|
+ const endTime = new Date(time)
|
|
|
+ const diffTime = endTime - startTime
|
|
|
+ return diffTime > 3 * 24 * 60 * 60 * 1000
|
|
|
+}
|
|
|
+const route = useRoute()
|
|
|
+const trajectory = ref([])
|
|
|
+const tabPosition = ref('load')
|
|
|
+const map = ref(null)
|
|
|
+const form = ref({})
|
|
|
+const rules = {
|
|
|
+ licensePlateNo: [{ required: true, message: '请输入车牌号', trigger: 'blur' }],
|
|
|
+ licensePlateColor: [{ required: true, message: '请选择车牌颜色', trigger: 'change' }],
|
|
|
+}
|
|
|
+const licensePlateColorList = [
|
|
|
+ { label: '蓝色', value: '蓝色' },
|
|
|
+ { label: '黄色', value: '黄色' },
|
|
|
+ { label: '黄绿色', value: '黄绿色' },
|
|
|
+ { label: '白色', value: '白色' },
|
|
|
+ { label: '绿色', value: '绿色' },
|
|
|
+]
|
|
|
+
|
|
|
+const restaurants = ref([])
|
|
|
+const querySearch = (queryString, cb) => {
|
|
|
+ const results = queryString ? restaurants.value.filter(createFilter(queryString)) : restaurants.value
|
|
|
+ // call callback function to return suggestions
|
|
|
+ cb(results)
|
|
|
+}
|
|
|
+const createFilter = queryString => {
|
|
|
+ return restaurant => {
|
|
|
+ return restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0
|
|
|
+ }
|
|
|
+}
|
|
|
+const loadAll = () => {
|
|
|
+ return [{ value: '蒙L22887' }, { value: '蒙L83719' }]
|
|
|
+}
|
|
|
+
|
|
|
+const initMap = () => {
|
|
|
+ AMapLoader.load({
|
|
|
+ key: '81a1282308f1aae58082425a1ebb91b0',
|
|
|
+ version: '2.0',
|
|
|
+ plugins: ['AMap.MoveAnimation'],
|
|
|
+ })
|
|
|
+ .then(AMap => {
|
|
|
+ AMap.plugin('AMap.MoveAnimation', () => {
|
|
|
+ map.value = new AMap.Map('container3', {
|
|
|
+ center: [116.397428, 39.90923],
|
|
|
+ })
|
|
|
+ })
|
|
|
+ })
|
|
|
+ .catch(e => {
|
|
|
+ console.error(e)
|
|
|
+ })
|
|
|
+}
|
|
|
+const data = ref(null)
|
|
|
+const parkArray = ref([])
|
|
|
+const totalMin = ref(0)
|
|
|
+const showTable = ref(false)
|
|
|
+const queryWaybill = async () => {
|
|
|
+ if (!form.value.licensePlateNo) {
|
|
|
+ return Message.error('请输入车牌号')
|
|
|
+ }
|
|
|
+ if (!form.value.startTime || !form.value.endTime) {
|
|
|
+ return Message.error('请选择时间范围')
|
|
|
+ }
|
|
|
+ if (!form.value.licensePlateColor) {
|
|
|
+ return Message.error('请选择车牌颜色')
|
|
|
+ }
|
|
|
+ console.log(form.value, '查询参数')
|
|
|
+ const params = {
|
|
|
+ licensePlateNo: form.value.licensePlateNo,
|
|
|
+ licensePlateColor: form.value.licensePlateColor,
|
|
|
+ startTime: form.value.startTime,
|
|
|
+ endTime: form.value.endTime,
|
|
|
+ }
|
|
|
+ const res = await tms.truckTrackQuery(params)
|
|
|
+
|
|
|
+ if (res.code == 101) {
|
|
|
+ if (res.data.status !== 1001) {
|
|
|
+ Message.error(res.data.result)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ data.value = res.data
|
|
|
+ if (data.value.result && data.value.result.trackArray) {
|
|
|
+ parkArray.value = data.value.result.parkArray
|
|
|
+ parkArray.value.forEach(item => {
|
|
|
+ totalMin.value += Number(item.parkMins)
|
|
|
+ })
|
|
|
+ data.value.result.trackArray.forEach(item => {
|
|
|
+ if (!isNaN(item.lon) && !isNaN(item.lat)) {
|
|
|
+ trajectory.value.push(transformFromWGSToGCJArr(Number(item.lon) / 600000, Number(item.lat) / 600000))
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ // 清除之前的markers
|
|
|
+ map.value.clearMap()
|
|
|
+ var polyline = new AMap.Polyline({
|
|
|
+ map: map.value,
|
|
|
+ path: trajectory.value,
|
|
|
+ showDir: true,
|
|
|
+ strokeColor: '#28F', //线颜色
|
|
|
+ strokeWeight: 6, //线宽
|
|
|
+ })
|
|
|
+ map.value.setFitView()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 添加marker
|
|
|
+const addMarker = data => {
|
|
|
+ data.forEach(item => {
|
|
|
+ const marker = new AMap.Marker({
|
|
|
+ position: item,
|
|
|
+ icon: require('@/assets/images/dian.png'), // 自定义图标
|
|
|
+ offset: new AMap.Pixel(-13, -26),
|
|
|
+ })
|
|
|
+ marker.setMap(map.value)
|
|
|
+ map.value.setFitView()
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// 清除markers
|
|
|
+const clearMarkers = () => {
|
|
|
+ map.value.clearMap()
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(async () => {
|
|
|
+ restaurants.value = loadAll()
|
|
|
+ await initMap()
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.mapMark {
|
|
|
+ position: relative;
|
|
|
+ // padding: 20px;
|
|
|
+ #container3 {
|
|
|
+ width: 100%;
|
|
|
+ height: 78vh;
|
|
|
+ }
|
|
|
+ .btnBox {
|
|
|
+ width: 100%;
|
|
|
+ position: absolute;
|
|
|
+ top: 10px;
|
|
|
+ left: 20px;
|
|
|
+ z-index: 100;
|
|
|
+ // width: 200px;
|
|
|
+ border-radius: 5px;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|
|
|
+<style lang="scss">
|
|
|
+.amap-icon {
|
|
|
+ width: 40px !important;
|
|
|
+ height: 40px !important;
|
|
|
+}
|
|
|
+.amap-icon img {
|
|
|
+ width: 40px !important;
|
|
|
+ height: 40px !important;
|
|
|
+}
|
|
|
+.abnormal {
|
|
|
+ text-align: right;
|
|
|
+ position: absolute;
|
|
|
+ width: 50%;
|
|
|
+ top: 45px;
|
|
|
+ right: 15px;
|
|
|
+ padding: 5px;
|
|
|
+ z-index: 10;
|
|
|
+ &-title {
|
|
|
+ padding: 5px;
|
|
|
+ background: #fff;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|